I spent a lot of time to find the answer to this question. Therefore, I am happy to help you.
1) Change the ExternalLogin method. Usually it looks like this:
if (hasRegistered) { Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie); ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager, OAuthDefaults.AuthenticationType); ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager, CookieAuthenticationDefaults.AuthenticationType); AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName); Authentication.SignIn(properties, oAuthIdentity, cookieIdentity); }
Now, in fact, you need to add refresh_token. The method will look like this:
if (hasRegistered) { Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie); ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager, OAuthDefaults.AuthenticationType); ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager, CookieAuthenticationDefaults.AuthenticationType); AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName); // ADD THIS PART var ticket = new AuthenticationTicket(oAuthIdentity, properties); var accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket); Microsoft.Owin.Security.Infrastructure.AuthenticationTokenCreateContext context = new Microsoft.Owin.Security.Infrastructure.AuthenticationTokenCreateContext( Request.GetOwinContext(), Startup.OAuthOptions.AccessTokenFormat, ticket); await Startup.OAuthOptions.RefreshTokenProvider.CreateAsync(context); properties.Dictionary.Add("refresh_token", context.Token); Authentication.SignIn(properties, oAuthIdentity, cookieIdentity); }
Now the refrehs token will be generated.
2) There is a problem of using the underlying context. Serialize Ticket in SimpleRefreshTokenProvider CreateAsync. Message from Bit Technology
It seems that in the ReceiveAsync method the .DeserializeTicket context is not returning an authentication ticket at all in the external login case. When I look at the context.Ticket property, then we call its null value. Comparing this to a local login, the DeserializeTicket method sets the context.Ticket property to AuthenticationTicket. So the secret is now how it happens DeserializeTicket behaves differently in two streams. A protected ticket string has been created in the database in the same CreateAsync method, which differs only in that I call this method manually in GenerateLocalAccessTokenResponse, against Owin middlware, calling it normal ... And neither SerializeTicket nor DeserializeTicket gives an error ...
So, you need to use Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer to search and deserialize the ticket. It will look like this:
Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer serializer = new Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer(); token.ProtectedTicket = System.Text.Encoding.Default.GetString(serializer.Serialize(context.Ticket));
instead:
token.ProtectedTicket = context.SerializeTicket();
And for the ReceiveAsync method:
Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer serializer = new Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer(); context.SetTicket(serializer.Deserialize(System.Text.Encoding.Default.GetBytes(refreshToken.ProtectedTicket)));
instead:
context.DeserializeTicket(refreshToken.ProtectedTicket);
3) Now you need to add refresh_token to the response of the ExternalLogin method. Override AuthorizationEndpointResponse in OAuthAuthorizationServerProvider. Something like that:
public override Task AuthorizationEndpointResponse(OAuthAuthorizationEndpointResponseContext context) { var refreshToken = context.OwinContext.Authentication.AuthenticationResponseGrant.Properties.Dictionary["refresh_token"]; if (!string.IsNullOrEmpty(refreshToken)) { context.AdditionalResponseParameters.Add("refresh_token", refreshToken); } return base.AuthorizationEndpointResponse(context); }
So ... thatβs it! Now, by calling the ExternalLogin method, you get the URL: https: // localhost: 44301 / Account / ExternalLoginCallback? Access_token = ACCESS_TOKEN & token_type = bearer & expires_in = 300 & state = STATE & refresh_token = TICKET & returnUrl = URL
I hope this helps)