2

I have successfully configured MVC 5 with google's OAuth on the server side. However, I also want to perform javascript with the user's auth token, and I don't want to force them to revalidate for this feature.

How can I preserve the user's OAuth token to use when using the Client OAuth API?

Specifically- I want to load the logged in user's youtube subscriptions. This page has info about how to use both the server and client API, but I'm having trouble finding where in the server callback the token is present. I've looked around in the ExternalLoginCallback method of my AccountController for any info, but I can't figure out what data contains the token. If I can find it on the server side objects, I can expose those to the view to use with javascript calls, but I can't find where that token is.

2 Answers 2

8

You can customize the GoogleOAuth2AuthenticationOptions in your MVC5 Startup.Auth.cs file to request the offline Access Code and Refresh tokens for use against Google's OAuth2 api's.

in this example I am collecting the values passed from google to the OWIN OAuth2 middleware and adding them to claims accessible in your Callback method.

  var googleCreds = new GoogleOAuth2AuthenticationOptions
        {
            ClientId = "[replace with your google console issued client id]",
            ClientSecret = "[replace with your google console issued client secret]",

            Provider = new Microsoft.Owin.Security.Google.GoogleOAuth2AuthenticationProvider
            {
                OnApplyRedirect = context =>
                {


                    string redirect = context.RedirectUri;
                    redirect += "&access_type=offline";
                    redirect += "&approval_prompt=force";
                    redirect += "&include_granted_scopes=true";


                    context.Response.Redirect(redirect);

                },
                OnAuthenticated = context =>
                {
                    TimeSpan expiryDuration = context.ExpiresIn ?? new TimeSpan();
                    context.Identity.AddClaim(new Claim("urn:tokens:google:email", context.Email));
                    context.Identity.AddClaim(new Claim("urn:tokens:google:url", context.GivenName));
                    if (!String.IsNullOrEmpty(context.RefreshToken))
                    {
                        context.Identity.AddClaim(new Claim("urn:tokens:google:refreshtoken", context.RefreshToken));
                    }
                    context.Identity.AddClaim(new Claim("urn:tokens:google:accesstoken", context.AccessToken));
                    if (context.User.GetValue("hd") != null)
                    {

                        context.Identity.AddClaim(new Claim("urn:tokens:google:hd", context.User.GetValue("hd").ToString()));
                    }
                    context.Identity.AddClaim(new Claim("urn:tokens:google:accesstokenexpiry", DateTime.UtcNow.Add(expiryDuration).ToString()));

                    return System.Threading.Tasks.Task.FromResult<object>(null);
                }
            }
        };
        googleCreds.Scope.Add("openid");
        googleCreds.Scope.Add("email");

        app.UseGoogleAuthentication(googleCreds);

Now you can access these claim values from your callback method. For example:

   var loginInfo = AuthenticationManager.GetExternalLoginInfo();
string GoogleAccessCode = String.Empty;
if (loginInfo.ExternalIdentity.Claims.FirstOrDefault(c => c.Type.Equals("urn:tokens:google:accesstoken")) != null)
                    {
                       GoogleAccessCode = loginInfo.ExternalIdentity.Claims.FirstOrDefault(c => c.Type.Equals("urn:tokens:google:accesstoken")).toString();
                }

At beginning of the authentication sequence, or after you've finished with AuthenticationManager.GetExternalLoginInfo(), you can clear the external authentication cookie that's floating around to prevent any problematic duplicate cookies building up:

 if (Request.Cookies[".AspNet.ExternalCookie"] != null)
            {
                var c = new System.Web.HttpCookie(".AspNet.ExternalCookie");
                c.Expires = DateTime.Now.AddDays(-1);
                Response.Cookies.Add(c);
            }
Sign up to request clarification or add additional context in comments.

4 Comments

this got me a lot closer to the answer, but sometimes the AuthenticationManager.GetExternalLoginInfo(); just returns null, even after I've been authenticated. Any ideas?
How it seems to work is the middleware provider sets a cookie called ".AspNet.ExternalCookie", then redirects to your callback method. If the cookie is set, then the AuthenticationManager.GetExternalLoginInfo request works. Sometimes if you've been testing the sequence multiple times, there are multiple instances of the cookie, which causes a problem. My current practice is to clear any cookie called ".AspNet.ExternalCookie", either before starting the initial ChallengeResult sequence, or after receiving the Callback.
If you are still periodically getting null returned from GetExternalLoginInfo() then it may be this known Owin bug: stackoverflow.com/questions/22535146/…
Thanks for that link! I gave up on this after a while because I was having issues, i'll have to check this out when i can next week.
0

In the OAuth protocol, your app requests authorization to access resources which are identified by scopes, and assuming the user is authenticated and approves, your app receives short-lived access tokens which let it access those resources, and (optionally) refresh tokens to allow long-term access.

In your case you will need to store the access token provided when the user approved access to their YouTube resources. The normal token offers only one-hour access so also record the refresh token to enable longer sessions. Add the token server side into the http header and get your client side javascript to use this to get authenticated access to google apis.

For examples and basics on how to implement can copy lot of stuff from Google sites but think you are better off to read:

  1. Incremental authorisation on Using OAuth 2.0 for Web Server Applications

  2. Offline Access on same page as above for use of refresh tokens

  3. OAuth 2.0 overview and help for Google APIs Client Library for .NET

I am trying to build a framework right now that helps me store and retrieve google authenticator results for my users and found the info above and the links they contained really helpful, hope they help you too.

1 Comment

I understand that I need to store the token, I'm having trouble finding the token itself in the objects I have on the server side.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.