OAuth 2 Google API refresh token is null

自作多情 提交于 2019-12-04 14:10:43

问题


I am developing an Asp.NET MVC5 App following this Google sample code.

I want the app to be authenticated and create an accesstoken (Configure stage) by a user and later on I need to be able to call Google APis' (Directory API in my case) using a refresh token (without 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);
        }
}         

FlowMetadata implementation. (I have 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 invoke the IndexAsync controller, as there is no previous accesstoken for the user, it creates a new one after the user sign in to the Google account.
This is a sample accesstoken,

{"access_token":"ya29.5gBOszGO-oYJJt4YZfF6FeaZth1f69_.....","token_type":"Bearer","expires_in":3600,"Issued":"2014-12-24T16:02:32.014+05:30"}

Question1: Why there is no Refreshtoken stored with this? How can I retrieve a refreshtoken? Question 2: If I get the refreshtoken, how should I modify the code to create a new access token and call the API (when the accesstoken is expired)? [I referred to this question , but there was no proper answer for missing refresh token.


回答1:


Found the solution for Google API offline access to get the refresh token and use refresh token to create a new accesstoken,

Question1: Why there is no Refreshtoken stored with this? How can I retrieve a refreshtoken?

I have to set the access_type as offline (by default it is online) in the request. as mentioned here

I had to write my own implementation for GoogleAuthorizationCodeFlow class. Thanks to this post.

 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: ..ow should I modify 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);
     }

This worked for me! Hope this will help others....



来源:https://stackoverflow.com/questions/27684334/oauth-2-google-api-refresh-token-is-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!