I am using ASP.NET MVC 5 with OWIN.
I have done a lot of research and haven't found how to renew the access token using the refresh token.
My scenario is: The first time the user accesses my app, he or she grants access to the account I read the refresh token returned from the API. When the users come back to my app, I need to refresh the access token based on the "Refresh Token".
Could anybody provide some code?
Here is what I've achieved till now:
Startup.Auth.cs:
var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions
{
Caption = "Google+",
ClientId = Parameters.Instance.Authentication.oAuth.GooglePlus.ClientId,
ClientSecret = Parameters.Instance.Authentication.oAuth.GooglePlus.ClientSecret,
CallbackPath = new PathString("/oauth-login-return"),
Provider = new GoogleOAuth2AuthenticationProvider
{
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));
context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Identity.FindFirstValue(ClaimTypes.Email)));
context.Identity.AddClaim(new Claim("picture", context.User.GetValue("picture").ToString()));
context.Identity.AddClaim(new Claim("profile", context.User.GetValue("profile").ToString()));
context.Identity.AddClaim(
new Claim(Parameters.Instance.Authentication.oAuth.GooglePlus.AccessTokenClaimType,
context.AccessToken));
}
}
};
googleOAuth2AuthenticationOptions.Scope.Add("https://www.googleapis.com/auth/plus.login");
googleOAuth2AuthenticationOptions.Scope.Add("https://www.googleapis.com/auth/userinfo.email");
AuthenticationController:
[HttpPost]
[AllowAnonymous]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
RedirectIfAuthenticated();
return new ChallengeResult(provider, Url.Content("~/oauth-login-callback"));
}
[ActionName("oauth-login-back")]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
}
// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
private class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string provider, string redirectUri)
: this(provider, redirectUri, null)
{
}
private ChallengeResult(string provider, string redirectUri, string userId)
{
LoginProvider = provider;
RedirectUri = redirectUri;
UserId = userId;
}
private string LoginProvider { get; set; }
private string RedirectUri { get; set; }
private string UserId { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
Using a Refresh Token These client credentials and the refresh_token can be used to create a new value for the access_token . To refresh the access token, select the Refresh access token API call within the Authorization folder of the Postman collection. Next, click the Send button to request a new access_token .
Refresh Token are typically longer lived than Access Tokens and used to request a new Access Token without forcing user authentication. Unlike Access Tokens, Refresh Tokens are only used with the Authorization Server and are never sent to a web service.
When to use Refresh Tokens? The main purpose of using a refresh token is to considerably shorten the life of an access token. The refresh token can then later be used to authenticate the user as and when required by the application without running into problems such as cookies being blocked, etc.
This question isn't duplicate AT ALL. I hope this help others not spending days like I have spent.
After almost 4 days I have found out how to get a fresh access token in the google api using OWIN.
I'm going to post the solution, but first, I MUST say that what helped me to start getting a clue about my error was setting up the Debug Symbols for the Katana project. See this link: http://www.symbolsource.org/Public/Home/VisualStudio
This image show how to configure Debug Symbols Servers.
And this one shows the Katana Debug Symbols being loaded.
After that, I found out that my problem was that Google API was returning 403: Forbidden
"Access Not Configured. Please use Google Developers Console to activate the API for your project"
Then, found on stack overflow this post: "Access Not Configured. Please use Google Developers Console to activate the API for your project."
more specifically this Answer: https://stackoverflow.com/a/24401189/833846
After that, I went to Google Developers Console and setup up Google+ API
And then, voillá! It worked.
Now, the code to get a fresh access token using the refresh token (I haven't found any way to accomplish that using the OWIN API).
public static class TokenValidator
{
/// <summary>
/// Obtém um novo access token na API do google.
/// </summary>
/// <param name="clientId"></param>
/// <param name="clientSecret"></param>
/// <param name="refreshToken"></param>
/// <returns></returns>
public static GoogleRefreshTokenModel ValidateGoogleToken(string clientId, string clientSecret, string refreshToken)
{
const string url = "https://accounts.google.com/o/oauth2/token";
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", refreshToken)
};
var content = GetContentAsync(url, "POST", parameters);
var token = JsonConvert.DeserializeObject<GoogleRefreshTokenModel>(content);
return token;
}
private static string GetContentAsync(string url,
string method = "POST",
IEnumerable<KeyValuePair<string, string>> parameters = null)
{
return method == "POST" ? PostAsync(url, parameters) : GetAsync(url, parameters);
}
private static string PostAsync(string url, IEnumerable<KeyValuePair<string, string>> parameters = null)
{
var uri = new Uri(url);
var request = WebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
var postParameters = GetPostParameters(parameters);
var bs = Encoding.UTF8.GetBytes(postParameters);
using (var reqStream = request.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (var response = request.GetResponse())
{
var sr = new StreamReader(response.GetResponseStream());
var jsonResponse = sr.ReadToEnd();
sr.Close();
return jsonResponse;
}
}
private static string GetPostParameters(IEnumerable<KeyValuePair<string, string>> parameters = null)
{
var postParameters = string.Empty;
foreach (var parameter in parameters)
{
postParameters += string.Format("&{0}={1}", parameter.Key,
HttpUtility.HtmlEncode(parameter.Value));
}
postParameters = postParameters.Substring(1);
return postParameters;
}
private static string GetAsync(string url, IEnumerable<KeyValuePair<string, string>> parameters = null)
{
url += "?" + GetQueryStringParameters(parameters);
var forIdsWebRequest = WebRequest.Create(url);
using (var response = (HttpWebResponse)forIdsWebRequest.GetResponse())
{
using (var data = response.GetResponseStream())
using (var reader = new StreamReader(data))
{
var jsonResponse = reader.ReadToEnd();
return jsonResponse;
}
}
}
private static string GetQueryStringParameters(IEnumerable<KeyValuePair<string, string>> parameters = null)
{
var queryStringParameters = string.Empty;
foreach (var parameter in parameters)
{
queryStringParameters += string.Format("&{0}={1}", parameter.Key,
HttpUtility.HtmlEncode(parameter.Value));
}
queryStringParameters = queryStringParameters.Substring(1);
return queryStringParameters;
}
}
IMPORTANT 1: To get a refresh token you must set the "access_type" to "offline" in the "ExecuteResult" method, this way:
properties.Dictionary["access_type"] = "offline";
IMPORTANT 2: Once you get your refresh token, you must store it and in some secure source. Google API won't issue you a new refresh token, unless you set "approval_prompt" to "force" before you call the line (in the same method):
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
I also recommend taking a look at:
Google API Offline Access
Google OAUTH 2.0 Playground
Google API Discovery Check
Spent the last two days figuring out how to renew the access token myself. The answer is posted in another thread here:
How Google API V 3.0 .Net library and Google OAuth2 Handling refresh token
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With