OAuth 2 Google API refresh token is zero
I am developing an Asp.NET MVC5 application following this google code sample .
I want the application to authenticate and create a UI (Configure stage), and then I needed to call Google APis (the directory API in my case) with a refresh token (no user intervention, something like "offline").
Controller:
public async Task<ActionResult> IndexAsync(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).
AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
var service = new Google.Apis.Admin.Directory.directory_v1.DirectoryService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "My Application"
});
return View();
}
else
{
return new RedirectResult(result.RedirectUri);
}
}
Implementation of FlowMetadata. (I am using FiledataStore slightly modified (GoogleFileDataStore))
public class AppFlowMetadata : FlowMetadata
{
//Move to settings
static readonly string clientId = "xxxccnvofsdfsfoj.apps.googleusercontent.com";
static readonly string clientsecret = "xxxxxxxxxxLvtC6Qbqpp4x_";
static readonly string datastore = "AdminSDK.Api.Auth.Store";
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientsecret
},
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser, DirectoryService.Scope.AdminDirectoryUserAliasReadonly },
DataStore = new GoogleFileDataStore(datastore)
});
public override string GetUserId(Controller controller)
{
return ConfigHelper.UserID.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
When I call the IndexAsync controller, since the user has no previous access to it, it creates a new one after the user logs into their google account.
This is a sample of accesstoken,
{"access_token":"ya29.5gBOszGO-oYJJt4YZfF6FeaZth1f69_.....","token_type":"Bearer","expires_in":3600,"Issued":"2014-12-24T16:02:32.014+05:30"}
Question1: Why is there no Refreshtoken in it? How can I get a refreshtoken? Question 2: If I receive a refreshtoken, how do I change the code to create a new access token and call the API (when the accesstoken expires)? [I mentioned this question , but there was no correct answer for the missing refresh token.
source to share
Found a google API offline access solution to get the refresh token and use the refresh token to create a new accesstoken,
Question1: Why is there no Refreshtoken in it? How can I get a refreshtoken?
I need to set access_type to offline (it is online by default) in a request. as stated here
I had to write my own implementation for the GoogleAuthorizationCodeFlow class. Thanks to this article.
public class ForceOfflineGoogleAuthorizationCodeFlow : GoogleAuthorizationCodeFlow
{
public ForceOfflineGoogleAuthorizationCodeFlow(GoogleAuthorizationCodeFlow.Initializer initializer) : base(initializer) { }
public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
{
return new GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl))
{
ClientId = ClientSecrets.ClientId,
Scope = string.Join(" ", Scopes),
RedirectUri = redirectUri,
AccessType = "offline",
ApprovalPrompt = "force"
};
}
};
Question2: .. should I change the code to create a new access token and call the API?
//try to get results
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).
AuthorizeAsync(cancellationToken);
//// This bit checks if the token is out of date,
//// and refreshes the access token using the refresh token.
if (result.Credential.Token.IsExpired(SystemClock.Default))
{
Google.Apis.Auth.OAuth2.Responses.TokenResponse token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse();
//If the token is expired recreate the token
token = await result.Credential.Flow.RefreshTokenAsync(ConfigHelper.UserID.ToString(), result.Credential.Token.RefreshToken, CancellationToken.None);
//Get the authorization details back
result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);
}
It worked for me! Hope this helps others ...
source to share