Push message by Signalr when logged in - asp.net

I use cookie based authentication on ASP.NET 6.0.0 SPA template.
this.connection = new HubConnectionBuilder()
.withUrl(`${setting.baseUrl}/hub/store`)
.build();
await this.connection.start();
And I logged in on action controller as below. I skip password verification. This is just example.
[HttpPost]
public async Task<ActionResult> Login(LoginModel model)
{
var user = await userManager.FindByNameAsync(model.Username);
if (user is null)
{
user = new ApplicationUser();
await userManager.SetUserNameAsync(user, model.PublicKey);
var createResult = await userManager.CreateAsync(user);
if (!createResult.Succeeded)
return BadRequest(createResult);
}
var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, user.Id) };
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddDays(15)
};
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
await storeHub.Clients.User(user.Id).LoggedIn();
return Ok();
}
As you can see i push LoggedIn message for logged in user at the end of login process.
I call the endpoint by ajax request and i see that LoggedIn message is not triggered on client side.
But LoggedIn event is really working when i tested it on another authorized endpoint.
I suspect there is something different when it is tried in login process method.
Any help ?

If you use connectionid, I believe it will work fine.
For this issue, you can follow my steps to troubleshoot.
Set breakponit in this line await storeHub.Clients.User(user.Id).LoggedIn();.
In your Immediate Window, input Context.User.Identity.Name to check the vaule.
And check the value of user.Id .
Related Post
SignalR - Sending a message to a specific user using (IUserIdProvider) NEW 2.0.0

Related

How to store cookies in asp.net identity (web api)

I have Asp.net web Application project with WebApi and individuals user Account.
I implemented Registration and login, and I used angularjs in front end.
Now, I need to store cookies in browser.
I'm confuse if authentication based on cookies store cookies in browser?
In my project I authenticate users based on token.
I do research but it confuse me and I did't find a clear guide to store cookies using Asp.Net Identity webApi.
Here is where is user authenticate:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
/*
I tried the following but I get an error that Request doesn't exist
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, context.UserName));
var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
*/
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
I'm sorry, I'm new in Asp.net Identity.
If there is a clear guide to do this in Asp.Net Identity in WebApi (Not MVC)?
Note: I don't have LoginPath.
So you have a webApi that you use to authenticate your users and when your user is authenticated you get a jwt token, Right ? and you need to save that token in a cookie so that your front-end would use to make requests.
so here is a sample code i wrote to do just that is asp core api
in my aspcore API AccountsController => Login Action:
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginViewModel vm)
{
if (ModelState.IsValid)
{
var token = await _authenticationService.GenerateToken(vm);
if (token != null)
{
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
return Unauthorized();
}
return StatusCode(StatusCodes.Status403Forbidden, new { ErrorMessage = "wrong Email or password" });
}
the _authenticationService is a class that i wrote to generatae jwt token :
public async Task<JwtSecurityToken> GenerateToken(LoginViewModel vm)
{
if (!string.IsNullOrEmpty(vm.Email) && !string.IsNullOrEmpty(vm.Password))
{
var user = await _userManager.FindByEmailAsync(vm.Email);
var userRoles = await _userManager.GetRolesAsync(user);
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.GetSection("Secrets:SigningKey").Value));
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, vm.Email)
};
foreach (var roleName in userRoles)
{
claims.Add(new Claim(ClaimsIdentity.DefaultRoleClaimType, roleName));
};
if (user != null && await _userManager.CheckPasswordAsync(user, vm.Password))
{
var token = new JwtSecurityToken(
issuer: _configuration.GetSection("Secrets:issuer").Value,
audience: _configuration.GetSection("Secrets:audience").Value,
expires: DateTime.UtcNow.AddDays(20),
signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
claims: claims);
return token;
}
return null;
}
return null;
}
so in the code above you if you send a good credentials to your api you will get a jwt token back.
now you need to save that token in a cookie, to do that you need to create the cookie in your front-end not your web api.
so you might see this link in angular-university

ASP.NET Core Jwt implement signinmanager claims

I have implemented Jwt as a way to authenticate my user. However, I am stuck on how I can do certain things on my application with regards to roles. Currently my Jwt Token contains the users email, phone , id and a list of roles that they have.
What I do with that token is like this:
[TypeFilter(typeof(ValidateRolesFilter), Arguments = new object[] {
ApplicationGlobals.ApplicationSecretKey, RoleGlobals.SystemAdministrator
})]
public IActionResult Index()
{
return View();
}
My Typefilter contains a rest request that sends the token to another application to verify if my user can access that Function. However,
I am stuck when it comes to the view. I want to segment certain containers to be allowed to be viewed by certain users with certain roles.
I have an idea that if I were to add my users claims to the signinmanager just like a non jwt application, i would be able to get the claims from the httpcontext. However, I don't know if what I have can work with an application that uses jwt.
public async Task SignInUserAsync(TIdentityUser user, bool isPersistent, IEnumerable<Claim> customClaims)
{
var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
var identity = claimsPrincipal.Identity as ClaimsIdentity;
var claims = (from c in claimsPrincipal.Claims select c).ToList();
var savedClaims = claims;
foreach (var item in claims)
{
identity.RemoveClaim(item);
}
if (customClaims != null)
{
identity.AddClaim(savedClaims[0]);
identity.AddClaim(savedClaims[1]);
identity.AddClaim(savedClaims[2]);
identity.AddClaims(customClaims);
}
await _signInManager.Context.SignInAsync(IdentityConstants.ApplicationScheme,
claimsPrincipal,
new AuthenticationProperties { IsPersistent = isPersistent });
}
I am recently doing a cooperative project on JWT. I wrote a middlware, when ever the user request to the api, It is checked by the Authentication middleware. I read the userRole from db and put it in the identity priciple I am sharing the middleware codes.
In here I read the JWT middle part to extract the user information
public class AuthenticationMiddleware
{
private readonly RequestDelegate _next;
// Dependency Injection
public AuthenticationMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
string authHeader = context.Request.Headers["Authorization"];
if (authHeader != null)
{
int startPoint = authHeader.IndexOf(".") + 1;
int endPoint = authHeader.LastIndexOf(".");
var tokenString = authHeader.Substring(startPoint, endPoint - startPoint).Split(".");
var token = tokenString[0].ToString()+"==";
var credentialString = Encoding.UTF8
.GetString(Convert.FromBase64String(token));
// Splitting the data from Jwt
var credentials = credentialString.Split(new char[] { ':',',' });
// Trim this string.
var userRule = credentials[5].Replace("\"", "");
var userName = credentials[3].Replace("\"", "");
// Identity Principal
var claims = new[]
{
new Claim("name", userName),
new Claim(ClaimTypes.Role, userRule),
};
var identity = new ClaimsIdentity(claims, "basic");
context.User = new ClaimsPrincipal(identity);
}
await _next(context);
}
}
In startup.cs you need to call this middleware in the configure method
app.UseMiddleware<AuthenticationMiddleware>();
In the controller
[HttpGet("GetUsers")]
[Authorize(Roles = "admin")]
public ActionResult GetUsers()
{
var users = _authRepository.GetUsers();
return Ok(users);
}
if You need any help please give a comment. This implementation really worked for me. Check my repositories on the subject: https://github.com/hidayatarg/Asp.net-Core-2.1-Jwt-Authentication-Middleware
https://github.com/hidayatarg/Decode-JWT-Token
JSON Web Tokens consist of three parts separated by dots (.), which are: Header,Payload,Signature .Therefore, a JWT typically looks like xxxxx.yyyyy.zzzzz .The second part of the token is the payload, which contains the claims.
You can decode the access token to get the claims which related to your roles :
How to decode JWT Token? .
Decoding and verifying JWT token using System.IdentityModel.Tokens.Jwt
If you are using Owin OpenID Connect middlerware to autheticate user from identity provider like Azure AD , Idenity server 4.... You can add additional claims to principal under OnTokenValidated event .
Edit :
You can also add the claims(decode and get the claims) to user context before sign- in :
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, loginData.Username));
identity.AddClaim(new Claim(ClaimTypes.Name, loginData.Username));
//add your custom claims
....
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { IsPersistent = loginData.RememberMe });
Reference : http://future-shock.net/blog/post/creating-a-simple-login-in-asp.net-core-2-using-authentication-and-authorization-not-identity
Then you can access the claims in view like :
#foreach (var item in Context.User.Claims)
{
<p>#item.Value</p>
};

ASP.NET Core Identity JWT always unauthorized

I'm following FullStack Mark's guide to setup an aspnet core with identity and angular, the problem is that i'm not getting the authorization part to work, i always get an 401 unauthorized, registering is working, and logging in is working too, i think that the problem may be in the generated token (it says invalid signature in jwt.io validation)
sorry if the question is poorly formulated, first time asking.
FullStack Mark's guide that i'm following: https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login
my entire application code : https://github.com/GiovaniHarada/AngularConce/tree/master/Conce
Login Controller
[HttpPost("login")]
public async Task<IActionResult> Post([FromBody]CredentialsResource credentials)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password);
if (identity == null)
{
return BadRequest(Errors.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState));
}
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, credentials.UserName, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}
Get Claims Identity
private async Task<ClaimsIdentity> GetClaimsIdentity(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
return await Task.FromResult<ClaimsIdentity>(null);
// get the user to verifty
var userToVerify = await _userManager.FindByNameAsync(userName);
if (userToVerify == null) return await Task.FromResult<ClaimsIdentity>(null);
// check the credentials
if (await _userManager.CheckPasswordAsync(userToVerify, password))
{
return await Task.FromResult(_jwtFactory.GenerateClaimsIdentity(userName, userToVerify.Id));
}
// Credentials are invalid, or account doesn't exist
return await Task.FromResult<ClaimsIdentity>(null);
}
Generate Encoded Token function
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}

asp.net mvc API get facebook token

I've created an application with asp.net mvc api with users, following this tutorial. And everything works great like that. local users and facebook login works fine.
But now I'm trying to use the FacebookClient and get the user info and friends.
But it asks me for the token, but is not the same token that is stored on my session or cookie.
In api controller Account, in GetExternalLogin action I have this code:
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);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
Here I can find the claims. But not how to use this
My question is how can I store the facebook token on my api after the login?
var options = new FacebookAuthenticationOptions
{
AppId = "Your App ID",
AppSecret = "Your App Secret",
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = async context =>
{
// Retrieve the OAuth access token to store for subsequent API calls
string accessToken = context.AccessToken;
// Retrieve the username
string facebookUserName = context.UserName;
// You can even retrieve the full JSON-serialized user
var serializedUser = context.User;
}
}
};
app.UseFacebookAuthentication(options);
For more info on how to do this stuff see here: http://www.oauthforaspnet.com/providers/facebook/
f the OnAuthenticated you could also add:
context.Identity.AddClaim(new Claim("FacebookToken", accessToken));
As I am pretty sure that at this point we have created the user and created their claims so you

How to create Refresh Token with External Login Provider?

I have searched over the web and could not find a solution to my problem. I am implementing OAuth in my app. I am using ASP .NET Web API 2, and Owin. The scenario is this, once a user request to the Token end point, he or she will receive an access token along with a refresh token to generate a new access token. I have a class the helps me to generate a refresh token. Here is it :
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var refreshTokenId = Guid.NewGuid().ToString("n");
using (AuthRepository _repo = new AuthRepository())
{
var refreshTokenLifeTime = context.OwinContext.Get<string> ("as:clientRefreshTokenLifeTime");
var token = new RefreshToken()
{
Id = Helper.GetHash(refreshTokenId),
ClientId = clientid,
Subject = context.Ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(15)
};
context.Ticket.Properties.IssuedUtc = token.IssuedUtc;
context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;
token.ProtectedTicket = context.SerializeTicket();
var result = await _repo.AddRefreshToken(token);
if (result)
{
context.SetToken(refreshTokenId);
}
}
}
// this method will be used to generate Access Token using the Refresh Token
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
string hashedTokenId = Helper.GetHash(context.Token);
using (AuthRepository _repo = new AuthRepository())
{
var refreshToken = await _repo.FindRefreshToken(hashedTokenId);
if (refreshToken != null )
{
//Get protectedTicket from refreshToken class
context.DeserializeTicket(refreshToken.ProtectedTicket);
// one refresh token per user and client
var result = await _repo.RemoveRefreshToken(hashedTokenId);
}
}
}
public void Create(AuthenticationTokenCreateContext context)
{
throw new NotImplementedException();
}
public void Receive(AuthenticationTokenReceiveContext context)
{
throw new NotImplementedException();
}
}
now i am allowing my users to register through facebook. Once a user register with facebook, I generate an access token and give it to him. Should I generate a refresh token as well ? Onething comes to my mind, is to generate a long access token like one day, then this user has to login with facebook again. But if i do not want to do that, I can give the client, a refresh token, and he can use it to refresh the generated access token and get a new. How do I create the refresh token and attach it to the response when someone register or login with facebook or externally ?
Here is my external registration API
public class AccountController : ApiController
{
[AllowAnonymous]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var accessTokenResponse = GenerateLocalAccessTokenResponse(model.UserName);
return Ok(accessTokenResponse);
}
}
// Private method to generate access token
private JObject GenerateLocalAccessTokenResponse(string userName)
{
var tokenExpiration = TimeSpan.FromDays(1);
ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
identity.AddClaim(new Claim("role", "user"));
var props = new AuthenticationProperties()
{
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.Add(tokenExpiration),
};
var ticket = new AuthenticationTicket(identity, props);
var accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
JObject tokenResponse = new JObject(
new JProperty("userName", userName),
new JProperty("access_token", accessToken),
// Here is what I need
new JProperty("resfresh_token", GetRefreshToken()),
new JProperty("token_type", "bearer"),
new JProperty("refresh_token",refreshToken),
new JProperty("expires_in", tokenExpiration.TotalSeconds.ToString()),
new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
);
return tokenResponse;
}
I spent a lot of time to find the answer to this question. So, i'm happy to help you.
1) Change your ExternalLogin method.
It usually looks like:
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, actually, it is necessary to add refresh_token.
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 to use basic context.SerializeTicket in SimpleRefreshTokenProvider CreateAsync method.
Message from Bit Of Technology
Seems in the ReceiveAsync method, the context.DeserializeTicket is not
returning an Authentication Ticket at all in the external login case.
When I look at the context.Ticket property after that call it’s null.
Comparing that to the local login flow, the DeserializeTicket method
sets the context.Ticket property to an AuthenticationTicket. So the
mystery now is how come the DeserializeTicket behaves differently in
the two flows. The protected ticket string in the database is created
in the same CreateAsync method, differing only in that I call that
method manually in the GenerateLocalAccessTokenResponse, vs. the Owin
middlware calling it normally… And neither SerializeTicket or
DeserializeTicket throw an error…
So, you need to use Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer to searizize and deserialize ticket.
It will be 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 of:
token.ProtectedTicket = context.SerializeTicket();
And for 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 of:
context.DeserializeTicket(refreshToken.ProtectedTicket);
3) Now you need to add refresh_token to ExternalLogin method response.
Override AuthorizationEndpointResponse in your OAuthAuthorizationServerProvider. Something like this:
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.. thats all! Now, after calling ExternalLogin method, you get 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)
#giraffe and others offcourse
A few remarks. There's no need to use the custom tickerserializer.
The following line:
Microsoft.Owin.Security.Infrastructure.AuthenticationTokenCreateContext context =
new Microsoft.Owin.Security.Infrastructure.AuthenticationTokenCreateContext(
Request.GetOwinContext(),
Startup.OAuthOptions.AccessTokenFormat, ticket);
As tokenformat: Startup.OAuthOptions.AccessTokenFormat is used. Since we want to provide a refeshtoken this needs te be changed to: Startup.OAuthOptions.RefreshTokenFormat
Otherwise if you want to get a new accesstoken and refresh the refreshtoken ( grant_type=refresh_token&refresh_token=...... ) the deserializer/unprotector will fail. Since it uses the wrong purposes keywords at the decrypt stage.
Finally found the solution for my problem.
First of all, if you EVER encounter any problems with OWIN and you cannot figure out what is going wrong, I advise you to simply enable symbol-debugging and debug it. A great explanation can be found here:
http://www.symbolsource.org/Public/Home/VisualStudio
My mistake simply was, that I was calculating a wrong ExiresUtc when using external login providers. So my refreshtoken basically was always expired right away....
If you are implementing refresh tokens, then look at this gread blog article:
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
And to make it work with refresh tokens for external providers, you have to set the two requried parameters ("as:clientAllowedOrigin" and "as:clientRefreshTokenLifeTime") on the context
so instead of
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
var 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);
you need to get the client first and set the context parameters
// retrieve client from database
var client = authRepository.FindClient(client_id);
// only generate refresh token if client is registered
if (client != null)
{
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
var context = new AuthenticationTokenCreateContext(Request.GetOwinContext(), AuthConfig.OAuthOptions.RefreshTokenFormat, ticket);
// Set this two context parameters or it won't work!!
context.OwinContext.Set("as:clientAllowedOrigin", client.AllowedOrigin);
context.OwinContext.Set("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());
await AuthConfig.OAuthOptions.RefreshTokenProvider.CreateAsync(context);
properties.Dictionary.Add("refresh_token", context.Token);
}

Resources