This is the third part of Building Simple Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and AngularJS. The topics we’ll cover are:
- Configure ASP.NET Identity with ASP.NET Web API (Accounts Management) – Part 1.
- ASP.NET Identity 2.1 Accounts Confirmation, and Password/User Policy Configuration – Part 2.
- Implement JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 – (This Post)
- ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4
- ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
- AngularJS Authentication and Authorization with ASP.NET Web API and Identity 2.1 – Part 6
The source code for this tutorial is available on GitHub.
Implement JSON Web Tokens Authentication in ASP.NET Web API and and Identity 2.1
Currently our API doesn’t support authentication and authorization, all the requests we receive to any end point are done anonymously, In this post we’ll configure our API which will act as our Authorization Server and Resource Server on the same time to issue JSON Web Tokens for authenticated users and those users will present this JWT to the protected end points in order to access it and process the request.
I will use step by step approach as usual to implement this, but I highly recommend you to read the post JSON Web Token in ASP.NET Web API 2 before completing this one; where I cover deeply what is JSON Web Tokens, the benefits of using JWT over default access tokens, and how they can be used to decouple Authorization server from Resource server. In this tutorial and for the sake of keeping it simple; both OAuth 2.0 roles (Authorization Server and Recourse Server) will live in the same API.
Step 1: Implement OAuth 2.0 Resource Owner Password Credential Flow
We are going to build an API which will be consumed by a trusted client (AngularJS front-end) so we only interested in implementing a single OAuth 2.0 flow where the registered user will present username and password to a specific end point, and the API will validate those credentials, and if all is valid it will return a JWT for the user where the client application used by the user should store it securely and locally in order to present this JWT with each request to any protected end point.
The nice thing about this JWT that it is a self contained token which contains all user claims and roles inside it, so there is no need to do any extra DB queries to fetch those values for the authenticated user. This JWT token will be configured to expire after 1 day of its issue date, so the user is requested to provide credentials again in order to obtain new JWT token.
If you are interested to know how to implement sliding expiration tokens and how you can keep the user logged in; I recommend you to read my other post Enable OAuth Refresh Tokens in AngularJS App which covers this deeply, but adds more complexity to the solution. To keep this tutorial simple we’ll not add refresh tokens here but you can refer to the post and implement it.
To implement the Resource Owner Password Credential flow; we need to add new folder named “Providers” then add a new class named “CustomOAuthProvider”, after you add then paste the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class CustomOAuthProvider : OAuthAuthorizationServerProvider { public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); return Task.FromResult<object>(null); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { var allowedOrigin = "*"; context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin }); 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; } if (!user.EmailConfirmed) { context.SetError("invalid_grant", "User did not confirm email."); return; } ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT"); var ticket = new AuthenticationTicket(oAuthIdentity, null); context.Validated(ticket); } } |
This class inherits from class “OAuthAuthorizationServerProvider” and overrides the below two methods:
- As you notice the “ValidateClientAuthentication” is empty, we are considering the request valid always, because in our implementation our client (AngularJS front-end) is trusted client and we do not need to validate it.
- The method “GrantResourceOwnerCredentials” is responsible for receiving the username and password from the request and validate them against our ASP.NET 2.1 Identity system, if the credentials are valid and the email is confirmed we are building an identity for the logged in user, this identity will contain all the roles and claims for the authenticated user, until now we didn’t cover roles and claims part of the tutorial, but for the mean time you can consider all users registered in our system without any roles or claims mapped to them.
- The method “GenerateUserIdentityAsync” is not implemented yet, we’ll add this helper method in the next step. This method will be responsible to fetch the authenticated user identity from the database and returns an object of type “ClaimsIdentity”.
- Lastly we are creating an Authentication ticket which contains the identity for the authenticated user, and when we call “context.Validated(ticket)” this will transfer this identity to an OAuth 2.0 bearer access token.
Step 2: Add method “GenerateUserIdentityAsync” to “ApplicationUser” class
Now we’ll add the helper method which will be responsible to get the authenticated user identity (all roles and claims mapped to the user). The “UserManager” class contains a method named “CreateIdentityAsync” to do this task, it will basically query the DB and get all the roles and claims for this user, to implement this open class “ApplicationUser” and paste the code below:
1 2 3 4 5 6 7 |
//Rest of code is removed for brevity public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType) { var userIdentity = await manager.CreateIdentityAsync(this, authenticationType); // Add custom user claims here return userIdentity; } |
Step 3: Issue JSON Web Tokens instead of Default Access Tokens
Now we want to configure our API to issue JWT tokens instead of default access tokens, to understand what is JWT and why it is better to use it, you can refer back to this post.
First thing we need to installed 2 NueGet packages as the below:
1 2 |
Install-package System.IdentityModel.Tokens.Jwt -Version 4.0.1 Install-package Thinktecture.IdentityModel.Core -Version 1.3.0 |
There is no direct support for issuing JWT in ASP.NET Web API, so in order to start issuing JWTs we need to implement this manually by implementing the interface “ISecureDataFormat” and implement the method “Protect”.
To implement this add new file named “CustomJwtFormat” under folder “Providers” and paste the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket> { private readonly string _issuer = string.Empty; public CustomJwtFormat(string issuer) { _issuer = issuer; } public string Protect(AuthenticationTicket data) { if (data == null) { throw new ArgumentNullException("data"); } string audienceId = ConfigurationManager.AppSettings["as:AudienceId"]; string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"]; var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64); var signingKey = new HmacSigningCredentials(keyByteArray); var issued = data.Properties.IssuedUtc; var expires = data.Properties.ExpiresUtc; var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey); var handler = new JwtSecurityTokenHandler(); var jwt = handler.WriteToken(token); return jwt; } public AuthenticationTicket Unprotect(string protectedText) { throw new NotImplementedException(); } } |
What we’ve implemented in this class is the following:
- The class “CustomJwtFormat” implements the interface “ISecureDataFormat<AuthenticationTicket>”, the JWT generation will take place inside method “Protect”.
- The constructor of this class accepts the “Issuer” of this JWT which will be our API. This API acts as Authorization and Resource Server on the same time, this can be string or URI, in our case we’ll fix it to URI.
- Inside “Protect” method we are doing the following:
- As we stated before, this API serves as Resource and Authorization Server at the same time, so we are fixing the Audience Id and Audience Secret (Resource Server) in web.config file, this Audience Id and Secret will be used for HMAC265 and hash the JWT token, I’ve used this implementation to generate the Audience Id and Secret.
- Do not forget to add 2 new keys “as:AudienceId” and “as:AudienceSecret” to the web.config AppSettings section.
- Then we prepare the raw data for the JSON Web Token which will be issued to the requester by providing the issuer, audience, user claims, issue date, expiry date, and the signing key which will sign (hash) the JWT payload.
- Lastly we serialize the JSON Web Token to a string and return it to the requester.
- By doing this, the requester for an OAuth 2.0 access token from our API will receive a signed token which contains claims for an authenticated Resource Owner (User) and this access token is intended to certain (Audience) as well.
Step 4: Add Support for OAuth 2.0 JWT Generation
Till this moment we didn’t configure our API to use OAuth 2.0 Authentication workflow, to do so open class “Startup” and add new method named “ConfigureOAuthTokenGeneration” as the below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
private void ConfigureOAuthTokenGeneration(IAppBuilder app) { // Configure the db context and user manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() { //For Dev enviroment only (on production should be AllowInsecureHttp = false) AllowInsecureHttp = true, TokenEndpointPath = new PathString("/oauth/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new CustomOAuthProvider(), AccessTokenFormat = new CustomJwtFormat("http://localhost:59822") }; // OAuth 2.0 Bearer Access Token Generation app.UseOAuthAuthorizationServer(OAuthServerOptions); } |
What we’ve implemented here is the following:
- The path for generating JWT will be as :”http://localhost:59822/oauth/token”.
- We’ve specified the expiry for token to be 1 day.
- We’ve specified the implementation on how to validate the Resource owner user credential in a custom class named “CustomOAuthProvider”.
- We’ve specified the implementation on how to generate the access token using JWT formats, this custom class named “CustomJwtFormat” will be responsible for generating JWT instead of default access token using DPAPI, note that both format will use Bearer scheme.
Do not forget to call the new method “ConfigureOAuthTokenGeneration” in the Startup “Configuration” as the class below:
1 2 3 4 5 6 7 8 9 |
public void Configuration(IAppBuilder app) { HttpConfiguration httpConfig = new HttpConfiguration(); ConfigureOAuthTokenGeneration(app); //Rest of code is removed for brevity } |
Our API currently is ready to start issuing JWT access token, so test this out we can issue HTTP POST request as the image below, and we should receive a valid JWT token for the next 24 hours and accepted only by our API.
Step 5: Protect the existing end points with [Authorize] Attribute
Now we’ll visit all the end points we have created earlier in previous posts in the “AccountsController” class, and attribute the end points which need to be protected (only authenticated user with valid JWT access token can access it) with the [Authorize] attribute as the below:
– GetUsers, GetUser, GetUserByName, and DeleteUser end points should be accessed by users enrolled in Role “Admin”. Roles Authorization is not implemented yet and for now we will only allow any authentication user to access it, the code change will be as simple as the below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[Authorize] [Route("users")] public IHttpActionResult GetUsers() {} [Authorize] [Route("user/{id:guid}", Name = "GetUserById")] public async Task<IHttpActionResult> GetUser(string Id) {} [Authorize] [Route("user/{username}")] public async Task<IHttpActionResult> GetUserByName(string username) { } [Authorize] [Route("user/{id:guid}")] public async Task<IHttpActionResult> DeleteUser(string id) { } |
– CreateUser and ConfirmEmail endpoints should be accessed anonymously always, so we need to attribute it with [AllowAnonymous] as the below:
1 2 3 4 5 6 7 8 9 10 11 12 |
[AllowAnonymous] [Route("create")] public async Task<IHttpActionResult> CreateUser(CreateUserBindingModel createUserModel) { } [AllowAnonymous] [HttpGet] [Route("ConfirmEmail", Name = "ConfirmEmailRoute")] public async Task<IHttpActionResult> ConfirmEmail(string userId = "", string code = "") { } |
– ChangePassword endpoint should be accessed by the authenticated user only, so we’ll attribute it with [Authorize] attribute as the below:
1 2 3 4 5 |
[Authorize] [Route("ChangePassword")] public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model) { } |
Step 6: Consume JSON Web Tokens
Now if we tried to obtain an access token by sending a request to the end point “oauth/token” then try to access one of the protected end points we’ll receive 401 Unauthorized status, the reason for this that our API doesn’t understand those JWT tokens issued by our API yet, to fix this we need to the following:
Install the below NuGet package:
1 |
Install-Package Microsoft.Owin.Security.Jwt -Version 3.0.0 |
The package “Microsoft.Owin.Security.Jwt” is responsible for protecting the Resource server resources using JWT, it only validate and de-serialize JWT tokens.
Now back to our “Startup” class, we need to add the below method “ConfigureOAuthTokenConsumption” as the below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private void ConfigureOAuthTokenConsumption(IAppBuilder app) { var issuer = "http://localhost:59822"; string audienceId = ConfigurationManager.AppSettings["as:AudienceId"]; byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]); // Api controllers with an [Authorize] attribute will be validated with JWT app.UseJwtBearerAuthentication( new JwtBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, AllowedAudiences = new[] { audienceId }, IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[] { new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret) } }); } |
This step will configure our API to trust tokens issued by our Authorization server only, in our case the Authorization and Resource Server are the same server (http://localhost:59822), notice how we are providing the values for audience, and the audience secret we used to generate and issue the JSON Web Token in step3.
By providing those values to the “JwtBearerAuthentication” middleware, our API will be able to consume only JWT tokens issued by our trusted Authorization server, any other JWT tokens from any other Authorization server will be rejected.
Lastly we need to call the method “ConfigureOAuthTokenConsumption” in the “Configuration” method as the below:
1 2 3 4 5 6 7 8 9 10 11 |
public void Configuration(IAppBuilder app) { HttpConfiguration httpConfig = new HttpConfiguration(); ConfigureOAuthTokenGeneration(app); ConfigureOAuthTokenConsumption(app); //Rest of code is here } |
Step 7: Final Testing
All the pieces should be in place now, to test this we will obtain JWT access token for the user “SuperPowerUser” by issuing POST request to the end point “oauth/token”
Then we will use the JWT received to access protected end point such as “ChangePassword”, if you remember once we added this end point, we were not able to test it directly because it was anonymous and inside its implementation we were calling the method “User.Identity.GetUserId()”. This method will return nothing for anonymous user, but after we’ve added the [Authorize] attribute, any user needs to access this end point should be authenticated and has a valid JWT.
To test this out we will issue POST request to the end point “/accounts/ChangePassword”as the image below, notice he we are sitting the Authorization header using Bearer scheme setting its value to the JWT we received for the user “SuperPwoerUser”. If all is valid we will receive 200 OK status and the user password should be updated.
The source code for this tutorial is available on GitHub.
In the next post we’ll see how we’ll implement Roles Based Authorization in our Identity service.
Follow me on Twitter @tjoudeh
References
- Understanding OWIN/Katana Authentication/Authorization Part I: Concepts by John Atten
- Featured Image Source
Per ususal, an excellent resource! Thanks for the back link!
Thank you John, I enjoy reading your concise posts too 🙂
Excellent, looking forward to the rest of the series!
Thanks Neil, glad to know it was useful 🙂
Excellent work, as always Taiseer. I’m really looking forward to the rest of this post series. Thanks for your hard work. 🙂
Thanks Toby, glad it was useful. Roles Authorization is the next post, so keep tuned 🙂
Thanks for the article!
Glad you liked it Rayan, I’ve received your email and will get back to you soon.
Taiseer.
Don’t worry about it. I ended up figuring it out. I had a controller on my API side (not my Resources side) that had the Authorize attribute on it. I was getting access denied because I hadn’t set up my API side to use JwtBearerAuthentication like I did with my Resources side. I’m all set!
Ryan
Great article, I am waiting for next.
Can you send me name or link to software you use to call API requests?…
This one you show on screens with Request and Response parameters.
Glad that u liked it, the Rest client called PostMan, it’s chrome extension.
Thx.
Thank you very much!!!!
Thank you. Excellent article. Excellent series. Looking forward to the remainder of the articles and seeing that AngularJS app going end-to-end with Web API.
Glad it it was useful, thanks for your comment.
Awesome! Waiting for the next post! When will it be aprox…?
Thanks for your message, hopefully next week, keep tuned 🙂
I want to tell my thoughts about membership. Asp.net Web Api membership is based on creating a new database schema for users, roles, etc. But if I have already a database(ecommerce,blog) that including users, roles but different schema. In this stuation, Should I need to implement and override Owin OAuth types like Identity, User, OAuth providers, etc.? This is tedious. The Web Api approach is based on creating new database. But in real world, developers are already database. And adaptation should so be easy.
Is there an end-to-end identity server available? Because I’ve been beating my head trying to get all of these parts to work together for days, and I’m getting really frustrated with the whole MS/OWIN stack. This is WAY harder and more complex than it has any right to be.
You can check the Identity Server v3, open source Authz server.
Excellent presentation. Thanks
Glad you liked it, thanks for your comment!
Thank you very much for this excellent tutorial. Although you explain this complex matter in a very clear and pleasant way, I am not capable to adapt your code in any way. Trying to jump from VB webforms to C# SPA, I will have to use – if that is allowed – your source as a ‘black box’ to handle authorization. Your solution seems to be much better en practical than the current Visual Studio templates.
Could you please explain how to generate the audience Id and secret in the web.config. I do not know what t do with the ‘implementation’ file.
Sure you can use the source code, as well the Audience Id is random string it can be Guid and the secret can be generated as this highlighted code
Simply fantastic , I am eagerly awaiting the next posts , thanks for the tutorials
Thanks for your message, finalizing the next post so should be published soon.
This would be even more awesome if you could also describe how to implement this in ASP.NET vnext. Can’t find anything on that 🙁
Meanwhile, the ASP.NET Identity 2.2 has been released. Any compatibility issue?
Nop, it is backward compatible and it contains bug fixes, check the release notes here.
In real world scenarios, is it wrong to let the resource and authorization server live in the same API? What are the pros(if any) and cons of this practice. Thank you
Hi Greg,
It depends on your business case and if yor will build multiple resource APIs that relies on Authorization server, if this is case then it is better to separate them to avoid any code redundancy and you will have the Authorization in once place, if your API is simple and your business usecase will not require you building different resource APIs then you can keep both in the same project, but I recommend separate them from the beginning and use JWT for this.
Again great tutorial! Can’t wait for the next one, when will you publish it?
BTW Any reason why you changed the naming convention from Repository (in your previous tutorials) to creating a Infrastructure folder with all the “repositories” in it? Readability perhaps?
After step 4 I when testing I get the error “Unsupported_grant_type”, Is there a way to fix this?
Elaborate more, this is showing when you are sending grant type not supported, the grant type used here is ‘Password’
sorry for the vague question.
Using Postman I am sending the following request
POST http://localhost:51624/oauth/token HTTP/1.1
Host: localhost:51624
Connection: keep-alive
Content-Length: 0
password: 0icu812
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
grant_type: Password
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36
username: SuperPowerUser
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _ga=GA1.1.378465731.1404751833
and getting the following response
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNca2VpdGhcZG9jdW1lbnRzXHZpc3VhbCBzdHVkaW8gMjAxM1xQcm9qZWN0c1xBc3BOZXRJZGVudGl0eVxBc3BOZXRJZGVudGl0eS5XZWJBcGlcb2F1dGhcdG9rZW4=?=
X-Powered-By: ASP.NET
Date: Tue, 17 Mar 2015 03:39:35 GMT
{“error”:”unsupported_grant_type”}
The code is identitical to what you have done in the tutorial, but I am not using LocalDB instead using SQLServer Express
Because I have manually entered your example instead of performing a clone of your repository it is possible I have a type O.
I am reusing your as:AudienceId and as:AudienceSecret keys instead of generating my own.
If you can suggest where in the code a mistake might cause this type of issue it would be appreciated.
Can anyone tell me where to at least start debugging this. Based on what I’m seeing on the net it looks like I’m doing this right.
I’ve tried but grant_type: Password and grant_type: password
any help would be appreciated.
I got the same problem when testing it after step four, the error is:
{
“error”: “unsupported_grant_type”
}
Can you help? I followed everything in the tutorial. Thanks.
Hi Bob, you still facing the errors? Make sure you are sending the request as the below, notice that Content-type header value:
POST /oauth/token HTTP/1.1
Host: localhost:59822
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
username=SuperPowerUser&password=MySuperP%40ss!&grant_type=password
I checked the request details and did not see any problem (although my username and password are different asI added the user to the db), the problem could be the keys of “as:AudienceId” and “as:audienceSecret”? As I see from your blog, and the other one with one authorization server and resource server that are in different project, these two keys were generated there by adding an audience to the authorization server, correct?
Thanks and really appreciate your help.
Ok, finally, get it work! I added a new user using Postman, and tried it using Postman without any headers, then it works. See here:
POST /oauth/token HTTP/1.1
Host: localhost:1281
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
username=bob&password=myP%40ss!&grant_type=password
but you mentioned adding headers as above? Thanks and really appreciate you help.
Another successful tutorial. Thank you Taiseer.
You welcome, glad you liked this series.
Hi Taiseer, I love this post and happens to be directly related to what I’m needing right now. However, I have one problem. I’ve created a resource server separate from the Authorization server and i’ve noticed that if I don’t specify an Authorization header, it allows the request through (even with the authorize attribute). If i specify an authorization header with a bad value, it will properly deny the request. Any ideas?
Hi Alex, that is strange, can you double check that you have those LOC in Startup correctly? Did you start Web API project from scratch or you used a template?
I’ve figured out what the problem was and it may be worth noting for others. I noticed on the response headers that the authorize header also had Negotiate and NTLM as authorization schemes. The IIS website instance I was installed under had them enabled, thus allowing authentication to occur. Once I turned them off, it worked as intended.
If you are in a situation where you cannot trust the user and/or the network, is there a way to add more security between the client app and the server and still use Oauth2?
For example, would using mac-based tokens help? I guess that only secures the transaction after the user receives the access key and mac key.
You can’t use hmac authentication in clients that can’t store the secret confidentially, so this will not work with the AngularJS application I’m going to build.
But if you use bearer-tokens, you also have to store them confidentially. So what’s the difference. This is actually not a disatvantage of Mac-tokens in my opinion, because you have to store any authorization-information anyway. So why not using Mac-tokens, to prevent sending the secret (bearer-token) over the wire on every request?
Storing secrets is different than storing bearer tokens. Bearer tokens expire and the access surface for it is limited, secrets or passwords is like a master key, if you put your hand on it you can control the entire account.
@Taiseer Joudeh
Yeah. Okay i understand your point. But as much as i know you can also configure mac-tokens to expire. An refresh token exist for both of them. So if you have a refresh bearer-token you also have unlimited access. Furthermore can you also configure limit the surface to access with mac-tokens. Its just configuration. In my opinion the token-technique itselft doesn’t define the access-surface. Or am i wrong?
Hi Taiseer,
I’ve enjoyed reading your blog post around identity and web api security. If you wanted to secure a api method so that it could be accessed only by known client_id & client_secrets, how would you do this.
An example would the create account method. We cant request that the user login to create and account but we want to restrict account creation to our known client_ids. Is there a correct way to do this or should the client_ID be passed in with the other new account information and handled inside the controller logic.
I have looked and I cant seem to find a attribute that will check only ValidateClientAuthentication as Authorize seems to be about the whole set of credentials.
Thanks for your feedback.
Hi Jermy,
Sending the client_id and client_secret depends on the type of the client you are building (Confidential/Non-Confidential), so for non-confidential clients you cant store the client secret. Now you can use ValidateClientAuthentication method and send the client_id and client_secret in the request and validate them before generating a access token, if this failed then you do not generate a token the consumer will not be able to access the end point.
Now in your case you need to special security to protect certain end point which only allows trusted clients to access it, well this reminds me of basic authentication where you send the username:password base64 encoded in the Authorization header with Basic scheme, and for this special end point you apply basic authentication authorize attribute, this post might be help.
Hi Taiseer, thanks for the tutorial! But I have one problem:
when I check get method api/users (or post method api/changePassord) with Authorization header (Bearer eyJ0eXAiO….)
I get an 401 Unauthorized status (“Authorization has been denied for this request.”)
how to fix it?
Hi Alex,
The api/ChangePassword endpoint should work if you have valid JWT (Not expired) but the api/users endpoint will work only when you obtain a token for user in “Admin” role, notice the [Authorize(Roles=”Admin”)] attribute.
JWT I check in jwt.io – signature verified, not expired
Attribute for endpoints ChangePassword and GetUsers – [Authorize]
But I get 401 status (((
Upload your code from GitHub – it works
I found an error
I had written:
AccessTokenFormat = new CustomJwtFormat(“http://localhost:4878/”)
must be:
AccessTokenFormat = new CustomJwtFormat(“http://localhost:4878”)
no character “/” at the end of string
Hi Taiseer!
There is one question:is it possible to find out the cause of invalid token (JWT)?
incorrect issuer, expired date etc.
I have done everything as per the article above but I get this error: “error”: “unsupported_grant_type”. Any ideas on what this is caused by and how to get around it?
Hi, I had the same error. Turned out I set username, password and grant_type as headers in the Advanced Rest Client instead of in the payload! 🙂
Hi Taiseer, thank you so much for your articles, they have taught me so much!!
I’m running into an issue that someone else mentioned in their comments. A return message of “Authorization has been denied for this request” when I attempt to do a change password call.
I ran Postman requests for createuser, and oauth/token and both of those succeeded, the latter producing a jwt token similar to what I believe I should be expecting ({ “access_token”: “eyJ0eXAiOiJ…”, “token_type”: “bearer”, “expires_in”: 86399}). However when I run the “http://localhost:63344/api/accounts/changepassword” call, I get the authorization denied error.
The one difference I made between my code and yours is that I set a public static string property on the CustomJwtFormat class that holds the “issuer” value. I did this so that I could be consistent everywhere with the Issuer value.
My questions are,
1) how exactly can I debug the underlying [Authorize] decorator? I’m sure that something is mismatched, but I have no idea where to look for that mismatch.
2) If “Issuer” can be anything (a string or URI), then what is the purpose of it? Is best practice to use any particular way? Is one more secure than the other?
Any help would be greatly appreciated! I need to figure this out before I can move on to your Claims tutorial.
Thanks so much again for all your write ups, I’ve learned SO MUCH from them.
Please disregard, I figured out what was going wrong. In the process of debugging and guessing changes, I had changed the static issuer property that I created to be different than when it granted the token. The site http://jwt.io that Alex mentioned actually helped me resolve the issue.
Thanks again! I’d still like to know if there is a best practice for the Issuer value and if there is a way to debug an authorize decorator, but now that I have it working, I can move on to the next article!
Great work. Very well documented.
I have a question here. I am using Thinktecture identity server v2 to get ouath tokens (Resource owner flow).
I am saving the access token received from thinktecuture server in a cookie on website.
passing the same cookie when doing ajax request to web api 2.2. What UseJwtBearerAuthentication I have to set up in web api?
Sorry for my silly question.
a reference & good article, but what about using Identity server http://identityserver.github.io/ , as alternative solution, what did you think about the level of maturity and extensibility, however in thinktecture, they are doing great stuff, but i found more sophisticated implementation, and even for the level of integration, and generally i don’t liked, but i have to stick to best available way to implement things, may i ask you for feedback and advice?
Hi Mohamed,
The Identity Server and what Dom and Brock built is amazing, it is full fledged and extensible Authorization server, but you need to understand what is doing so you can extend it and troubleshoot any issue facing when deploying/working on it.
The only previous take about identity server is the documentation and the absence of simple steps to install it, but I guess this has changed recently and things are mature and organised, the guys spent decent time updating the documentation and GitHub wikis.
So my recommendation is to use the identity server if you know what you are doing, but for someone want something quick and support minimal OAuth flows then he can depend on my post series.
Hope this helps.
Except when it comes to ASP.NET 5. I don’t believe they are going to implement the Oauth server in ASP.NET 5 so it sounds like the Identity Server is the way to go going forward. Let me know if I’ve misunderstood.
As always – Great post and much fun to read.
few questions /remarks :
1. Comparing this with the build-in template of WebAPI using VS2013 wizard there are minor changes, for example the VS template after setting the OAuthAuthorizationServerOptions options, calls the
app.UseOAuthBearerTokens(OAuthOptions) where your code uses app.UseOAuthAuthorizationServer(OAuthServerOptions);
what is the major diffrence between those two ?
also VS 2013 ApplicationOAuthProvider (which is the CustomOAuthProvider in your code) is calling context.Request.Context.Authentication.SignIn(cookiesIdentity); as the final code on GrantResourceOwnerCredentials.
Is that necessary ? I wonder why they did that , after all the API is stateless server, so why they are using this Autheticator.SignIn method ?
2. What is the easiest way to generate as:AudienceId and as:AudienceSecret ? are there any rules regarding their length ?
Thanks again.
disregard Question #2 it was already addressed in your JWT post. thanks !
Hello Taiseer, thanks for your great article on this topic.
I have a ASP.NET MVC 5 application with default form authentication with cookies for regular web client(with browser), how can I add token based authentication for web api client? What changes need to be made, added and where (which file)?
Thanks.
Great series of blog posts! Very clear and everything worked.
Glad to hear this, thanks for your message 🙂
Hi Taiser
Great article. I have worked my way successfully through part 1 and 2, I have run into problems at the “oauth/token” part, I am getting dreaded “IIS 8.0 Detailed Error – 404.0 – Not Found”, I have followed your tutorial to the letter. Is there something I missed?
In your example you set the AccessTokenExpireTimeSpan to 24 hours. Does each successful request using a valid token reset the AccessTokenExpireTimeSpan back to 24 hours?
No this is not sliding expiration time, it is the time that access token will live for, it will end after 24 hours after you issue it.
Very Nice Example 🙂
I am beginner in this and have to start with DB first approach. Say I am already using aspnetDB in my aplication
and I want to use it with that DB. How can I use this, any example you can provide.
Hi Garima, you can google how you can add AspNet Identity with existing DB, lot of articles covering this topic.
Excellent article. I have a question in context of Azure AD authentication. Your articles on that topic helped a lot. We are using Azure AD authentication in the project but not authorization. The application needs to add it’s own claims in the pipeline. These claims cannot be configured in Azure AD set up. The user management (adding removing users to application, creating access permissions based on security groups in AD etc.) is happening in Azure AD. However granting access to specific resources is defined in the application (essentially giving editing rights).
I am not sure where to plug the code (adding new claims to identity). GrantResourceOwnerCredentials is not part of the pipeline since I don’t need authorization server. I also get bearer token which is already validated. Which is the correct point? Also how can I cache these claims so that I don’t have to go to the DB for each request.
Thanks in advance.
Hi Hemant, thanks for your message. This is interesting question that I have no answer for it now. I’m not sure if you can use your own claims with Azure AD as the token you received is issued by Azure AD tenant, so it contains all the claims already. Maybe you can ask Vittorio who always welling to help when it comes to Azure AD.
As well check this repo which might help in your case.
I have followed your example but get 401 on CORS preflight request (OPTIONS)
Hey Taiseer, first I want to start with thank you so much for all your posts? It’s alot to digest but so far it’s all working (still trying to understand each part of it better tho haha). I do have a quick question for a scenario we have in our shop. We’re using a font-end ASP.NET Application and added all your security logic to the web api. Our workstations can be used by multiple users throughout the day as well
1- We’d like to kick users out due to inactivity. Should we just use a session timeout and kick them back to the login screen? Once they log in again a new token would be issue right?
2- Our management wants us to limit concurrent user access. So basically if I’m logged in to my computer, and then I log into another computer they would like the first computer not to have access anymore and be booted out. Do you have any thoughts on how that could be best achieved?
Thanks again for all your support!
Hi Chris, glad you found the posts useful.
For both questions you need to store a reference on the database for each user/token issued, so if user x obtained token at certain time and he keeps sending this token to the back-end Api, you need to store in the database the last time of using this token, and with each request you validate the timespan between what stored in DB and what time of the request, if it was longer than the time out you specified then server issue 401 response.
For the second question I guess you need to depend on the IP and store it inside the access token as claim, and with each request you need to make sure that the IP is not changed for the authenticated user.
Hope this makes sense.
Dear Instructor,
When I check your source code in github. I found in file “Web.config”:
I am just wondering how you get the value = “414e1927a3884f68abc79f7283837fd1” for AudienceId and the value = “qMCdFDQuF23RV1Y-1Gq9L3cF3VmuFwVbam4fMTdAfpo” for AudienceSecret.
Thank you!
if you are having this error {“error”:”unsupported_grant_type”}, then it means your post is not well formed. Just follow this step in postman.
1. The method should be POST.
2. Enter the URL eg. http://localhost:9811/oauth/token
3. Specify the following in the header
Key value
3.1 Content-Type application/x-www-form-urlencoded
3.1 Accept application/json
3.1 Post oauth/token http/1.1
3.1 Host localhost:your port(eg 9811)
4. Then go the body section. Select the raw option and type the following
username=smithsamuel&password=xxxxxxxxxxxxx(use your password)&grant_type=password
Then click on send.
Thanks for all your work in explaining this confusing space (as I can see from the amount of comments). Seems like there are a lot of way for inexperienced (and experienced alike) to miss something in this unforgiving space.
It might be worth mentioning that there are currently no plans to port OAuthAuthorizationServerMiddleware to asp vnext.
http://stackoverflow.com/questions/29055477/oauth-authorization-service-in-asp-net-mvc-6
Thanks for your message, I guess they will integrate the ThinkTecture Identity server in ASP.NET 5 (https://github.com/aspnet/Security/issues/83)
Thank you for this excellent series, I learned so much about security.
I am trying to combine the separation of Authorization and Resource servers with the refresh tokens and got a bit confused.
in the ValidateClientAuthentication method the client validation is used in two different ways in the cases above. WHat is the way to combine validating the audience (for separation) and the client (for refresh tokens)? Can I use a different key for audience? like ‘audience_id ?
TIA
Andrew
Hi Taiseer,
I don’t know why, I have always this return message:
“message”: “Authorization has been denied for this request.”
I have downloaded your code to test.
With postman I’m able to have a JWT Token calling “http://localhost:59822/oauth/token…”
But, when I put the code in Bearer style (Bearer xxxxxx) to change password or get user lists I receive always the above message.
Please help me.
thanks in advance
Nicola
Hi Nicola,
Make sure that all values in Step 6 for (Audience Id, Secret and Issuer) are the exact values (case sensitive) used in Step 4, I suspect that issuer value is different, please double check this.
Hi Taiseer,
Thanks for your posts and guidelines.
Quite helpful all the time and I have tried to read it all..
The question I have regarding this post is how does User.Identity gets read if we are using a JWT?
For example in the ChangePassword Method, you used User.Identity.GetUserID().
Thanks.
Hi,
If you noticed, this method is attributed by [Authorize] attribute, so only authenticated users with valid JWT tokens can access it, so there should be established identity and the the extension method GetUserId will return the authenticated UserId, check how we set it here.
Hi,
Great write up, I am really enjoying reading these posts on authentications, and learning a lot from it.
I am confused on audienceId, and audienceSecret, how did you generate those keys?
Regards
Hi, glad you find post useful.
Please check step 1.4 from this post and look at the code in method: AddAudience. I have generated the Audience Id and Secret for this post up front ans daved them in Web.config as I have only one Audience.
hi Taiseer,
I am a great fan of your blog.. I am (literally) following your code in my project.. but I am stuck at the consumption of my jwt token..at resurce api end
My hosting environment is like this,
domain.xxx/authServer
domain.xxx/ResrcServer
domain.xxx/webApps
IN WHICH EACH PROJECT/ APPLICATION AS VIRTUAL DIRECTORY
The thing is that token is successfully generated and all the information are there (after looking through http://jwt.io/) with some additional information like
“http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider”: “ASP.NET Identity”,
“AspNet.Identity.SecurityStamp”: “cc0177c1-349c-4bc9-842b-13561db52ba1”
BUT WHENEVER I TRIED TO ACCESS SOME API’S FROM MY RESOURCE SERVER (WHICH IS DECORATED WITH [AUTHORIZE ] DIRECTIVE I ALWAYS GET 401 ERROR .. ( I EVEN ENABLE CORS BUT WITH NOT SUCCESS AND EVEN TRIED THE API FROM CHROME POSTMAN… ).. SO PLZ GIVE SOME INPUTS OR HOW TO DEBUG THIS ERROR AND WHERE CAN THERE BE ERROR IN MY CODE AS … AGAIN PLZ AS THE PROJECT IS TIME BOUND…
my token consumption part is like this,
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var issuer = “http://domainxxx/authServer”;
string audienceId = ConfigurationManager.AppSettings[“as:AudienceId”];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings[“as:AudienceSecret”]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
THANKS IN ADVANCE
Hi Joy,
Glad to know that my code is useful for your case, well the only thing I suspect that the issuer, audienceId, or audience secret value in your resource api is different from your Auth server, make sure that issuer value is using the same protocol (http) with no trailing slash at the end.
To have a proper oauth 3-legged authentication every client needs to have registered a callback url. The server receives the client is and on validate clieny should redirect to this url with a temporary acess token. Then the client needs to call the server with this temporary token and then the servet must grant the permanent acess token Because all articles on asp.net web api seem to be neglectong this, would you be able to expand on your excellent article with this added step in oauth?
Thanks
Hi Milen, this is exactly the Authorization code grant, hopefully I will be able to extend this soon. Thanks for your comment
Hi, big up for your post. how can i extend CustomJwtFormat class constructor to allow multiple issuer.
Web with angular = “http://localhost:59822”
Android = ???
Sorry for the dummy question just a student trying to lurn
Hey Taiseer, your answers to my question helped..thanks again! Quick question, when I use jwt.io to decrypt my token I see that my user guid is in there as “nameid”: “c1e52007-777c-428a-a1eb-ce3a94d8d676”. I’m trying to figure out how to extract that in my controller after a user has been authorized.
ClaimsIdentity userIdentity = (ClaimsIdentity)User.Identity;
I noticed in ClaimsIdentity as I drill down deep into the results that the GUID is there but I’m not sure how to extract it properly without doing a bunch of string manipulation.
[0] {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: c1e52007-777c-428a-a1eb-ce3a94d8d676} System.Security.Claims.Claim
For now I add a claim with the guid as the value but I don’t think this should be necessary being that it’s in the token already
Hi Chris,
To get any claim from an established identity you can do as the code below:
var identity = User.Identity as ClaimsIdentity;
var userId = identity.Claims.First(i => i.Type == “YourClaimTypeHere”).Value;
Hope this answers your question.
Thats what I’m doing now – but I’m not sure if it’s necessary to add the guid for the user as a claim being that it’s already in the token. Here’s my token decrypted from my dev environment.. I’m trying to extract nameid
{
“nameid”: “c1e52007-777c-428a-a1eb-ce3a94d8d676”,
“unique_name”: “cmccrum”,
“http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider”: “ASP.NET Identity”,
“AspNet.Identity.SecurityStamp”: “a6d53dda-6c98-4b2c-b300-90484b2250b2”,
“role”: [
“Guru”,
“User”,
“Admin”
],
“VendorId”: “1”,
“iss”: “http://localhost/DeadBoltWebService”,
“aud”: “83d372ae2f844c4d93afa3bc8d3a1901”,
“exp”: 1439927694,
“nbf”: 1439841294
}
I tried var nameClaim = identity.Claims.Single(x => x.Type == “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier”); and that doesn’t work along with simply using nameid.
Hey Taiseer,
How to request a token to use in a service/server?
I try to use grant_type=client_credentials&client_id=CLICKID&client_secret=CLIENTSECRET&resource=WHATEVER
and i keep getting “error”: “unauthorized_client”
Any ideas? Do i have to config something in the OAuthAuthorizationServerOptions?
Thanks,
Valter
Hey Taiseer,
I figure out my issue… i didn’t override the GrantClientCredentials method.
Thanks,
Valter
Please check the grant “Client Credentials Grant” in this post, this should help you implementing client credential flow.
Thank you so much for the tutorial Taiseer! You explain an incredibly difficult topic in very easy terms.
I did run into one problem after tying all this in to a sample Angular App that I was building. Every so often, I’ll get this error “IDX 10223: Lifetime Validation Failed” that is tied to the JWT token (I’m assuming). My guess is that it’s an expired token on the server but somehow I need to catch this error in my client code. I wanted to track down where in my code it’s actually happening but my browsers start acting weird after I get the error. Chrome crashes if I open dev tools after getting this error (oddly enough, if I don’t open dev tools, the entire app works just fine). Visual Studio will throw an error from the code saying that the IDX error was encountered, but IE won’t let me navigate back to the code. Firefox Dev Edition throws, what seems to be, future errors that would occur if the token expired but doesn’t show me where the actual code is erroring out.
Do you have any thoughts on how to handle this error? Should I be catching it in my authentication code? Should I put an httpinterceptor in place in Angular that monitors for this error (I’m assumign its a 401 error ultimately)?
Any help would be greatly appreciated!
Hi Jacob,
That is really interesting issue, well if I were in your case, then I will try using http interceptor where I will be monitoring 401 response. But in any case if the JWT is expired the server should never throw an exception, it should return 401 only. To make sure of this, please try to use expired JWT in a request to protected resource using PostMan and check the response, it should only return 401.
Please share with me your solution, hope it will be an easy one.
Hi,
I have followed your tutorial. It’s awesome. But I have an issue.
When I try to Change the password. I pass the bearer token.
And I have a notimplemented exception on JwtFormat class in provider folder.
public AuthenticationTicket Unprotect(string protectedText)
Why is it going in this method?
How can I fix it?
Thanks,
Hi Alex,
I’m not sure if you implemented something incorrectly in this class, but are you receiving this exception for all protected endpoints or just this one?
Hi,
Thanks I could fix it. The nugget Microsoft.Owin.Security.Jwt -Version 3.0.0 was not installed.
Thanks!
Hi,
I can create my token with postman and it works perfectly but with my app it does not work.I have the error:
XMLHttpRequest cannot load http://localhost:7241/oauth/token. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:9000’ is therefore not allowed access. The response had HTTP status code 400.
I have enabled cors in my web api.
And in my angularjs app.js file:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common[‘X-Requested-With’];
// $httpProvider.defaults.withCredentials = true;
$httpProvider.interceptors.push(‘AuthInterceptor’);
I cannot sort it out. Any ideas?
I tried with chrome anf irefox.
Thanks,
Hi,
you need to allow it here too As well make sure you are using the same NuGet versions I’m using.
Hi Taiseer, This absolutely awesome. I do have a question, let’s say a third party untrusted client is trying to accessing the web api. So obviously, I don’t want the user to create their account and authenticate via the third party client, how can I make sure third party request redirects to my webapi backend, so that they can authenticate on my webapi and then go back to the third party client once done.
Hi Avi,
You need to use a different grant here which is the implicit flow or authorization code flow, where the user will enter his credentials not in the untrusted client, but directly in the authorization server. I didn’t implement this but this post will help you to achieve what you are looking for, or you can consider using the ThinkTecture Identity Server.
Thanks Taiseer. I’m thinking of looking at the Thinktecture Id server.
Great article, but I’m having trouble getting it to work.
I’ve made a test project based on this article and this (http://odetocode.com/blogs/scott/archive/2015/01/15/using-json-web-tokens-with-katana-and-webapi.aspx) article. The project succesfully creates a JWT token, but I cannot perform any requests using that token. I keep getting an HTTP 401 error. The problem is that I have no idea how to debug this inner process. It;s all handled by the Authorize attribute. Do you have any pointers how to troubleshoot this problem?
Thanks!
Hi Jeroen, this issued JWT token should be trusted by your resource APi, please check step 6 from my post and make sure that AudienceId, secret and issuer are all set correctly.
After building the complete Owin framework from source to be able to debug it, I was able to solve it.
I’m using Web API and I want my API calls to be authorized. A call with bearer token was denied constantly, even though I was able to get an OAuth token.
I put a breakpoint on AuthenticateCoreAsync() in OAuthBearerAuthenticationHandler from the Microsoft Owin security library I noticed it wouldn’t get hit. At all. As if the authentication middleware wasn’t loaded. I checked my implementation 10 times and it all seemed good. Per chance I requested the index page (which is just an empty directory) and then the breakpoint was hit! But for some reason, requesting the Web API endpoint didn’t work.
I then changed the order in which I loaded the middleware from:
app.UseWebApi(config);
app.UseJwtBearerAuthentication(new JwtOptions());
app.UseOAuthAuthorizationServer(new OAuthOptions());
to:
app.UseJwtBearerAuthentication(new JwtOptions());
app.UseOAuthAuthorizationServer(new OAuthOptions());
app.UseWebApi(config);
and then it worked….
I would’ve never thought the order would be important….
The order is indeed important! I was getting 401 too, and then changed the order from:
HttpConfiguration httpConfig = new HttpConfiguration();
ConfigureOAuthTokenGeneration(app);
ConfigureWebApi(httpConfig);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
ConfigureOAuthTokenConsumption(app);
To:
HttpConfiguration httpConfig = new HttpConfiguration();
ConfigureOAuthTokenConsumption(app);
ConfigureOAuthTokenGeneration(app);
ConfigureWebApi(httpConfig);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
and it worked!
Thank you so much for finding that out, you really saved hours of work for such a silly problem!
Taiseer, this is an excellent article, I have a question about how to customize the json web token consumption in a web api resource server, i want to not only validate the json web token receive on each request also i want to read the token received, which methods should i override in the web api resource server in order to perform the current json web token validation as the one you mentioned in this article and in the others, and implementing this kind of additional logic to it ?
Thanks for your articles, ill be waiting for your reply.
Hi Carols, I need to check this, if you find an answer please share it.
Hi, thank you for the great tutorial, it helped me a lot! Could you pls explain how exactly you implemented the as:AudienceId and Secret? How can I create the values for my application? And when using the function linked in the description, how should it be implemented into the application?
thanks in advance 🙂
Hi, I managed to solve the problem: using the x-www-form-urlencoded option for the body produces an error, using the raw tab instead solved the problem whereas I expected the audience-key to be the source of the problem.
greetings
Michael Heribert
You are welcome Michael, thanks for you comment and happy to hear you solved the issue.
Hi Michael
I’m trying to create my own audience id and secret, could you please tell me how you managed to create your own?
Thanks in advace!
I would like an answer to this too. It’s a great tutorial but this bit has left me a bit high and dry. Am I to build this class into another application to generate the values? Can you expand on this please?
TIA
Getting error testing out access token. The error is unsupported_grant_type.
Request: http://localhost:59822/oauth/token
Status
400 Bad Request Show explanation Loading time: 93
Request headers
username: SuperPowerUser
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
X-DevTools-Emulate-Network-Conditions-Client-Id: 186AD051-64D8-4890-9BBE-47F7B6309430
grant_type: password
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36
password: MySuperP@ssword!
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: __RequestVerificationToken_L2JvcmRlcnRpeA2=qA73L3FxlS562JBDGKjR-ch6bnrrlW-zFqx5ntdDAZPZpI7C9nOAoj4uRvDKPNYXepRSZJHOwixnlmp9forV22k0kn-atcTIfhi8AnJ4fwk1; __RequestVerificationToken=AqounhGRCOyT_drnSmV_aIsJQ8Nl0eRJkwECTarf079Iuqmi9AQVaeEXUMQ_0WH6B8KQW_j7lq-H5FxPBUPWZqRPaEXTNNfslOmdTDfzG4U1
Response headers
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcbWFya1xkb2N1bWVudHNcdmlzdWFsIHN0dWRpbyAyMDEzXFByb2plY3RzXFdlYkFwcDFcV2ViQXBwMVxvYXV0aFx0b2tlbg==?=
X-Powered-By: ASP.NET
Date: Sun, 20 Sep 2015 21:08:55 GMT
Raw
JSON
{“error”:”unsupported_grant_type”}
I did some research and most of the stuff I found said to add the existing line in GrantResourceOwnerCredentials()…
context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new[] { “*” });
Since this is already in CustomOAuthProvider.GrantResourceOwnerCredentials(), I’m kinda stuck.
Do you have any ideas?
thanks,
Hi. I guess username, passwod and grant_type should be sent in body not in headers
Hi Pepek, Nothing sent in the headers, it is sent in the body as UrlEncoded content type.
It is totally misleading message.
The real problem is that Password hash in User table wasn’t correct.
Put the following code in GrantResourceOwnerCredentials function of CustomOAuthProvider class:
var pHasher = new Microsoft.AspNet.Identity.PasswordHasher();
string hashed = pHasher.HashPassword(“HPSWD001”);
/* PUT BREAKPOINT TO FOLLOWING LINE and use watcher in debugger to inspect hashed variable
Compare hashed variable with the data stored in PasswordHash column in User table. It should be the same.
After I changed that, everything started to work. */
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
Hi
I have the same problem..
I try to add the code that suggest @Hrvoje but dosen’t work because the Hash password is differnt than ordifina password..
I try also to hard coded the usen name and password in line 35 in CustoOAuthProviders.cs
ApplicationUser user = await userManager.FindAsync(“SuperPowerUser”, “MySuperP@ss!”);
and hashed password
ApplicationUser user = await userManager.FindAsync(“SuperPowerUser”, “ANQ/JYqtnfCMmOHUMj9MZdXOhOpnqwVVJiik8A36jAr9jDyftg6OTtr5a0Q17toUlw==”);
But this method don’t found the user in the database and I don’t undestand…
I download the your source to compare the code and ara same
can you help me, please?
I had a problem when I accidently updated packages to latest versions for *.owin.* in PM. I meant to only update EF and the .net framework to 4.5.1. After updating I noticed that the method ‘public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)’ was not being called. I set a breakpoint in the method and it never hit when I tried making a REST client to call POST http://localhost:port/oauth/token with username, password, and grant_type params. Reverting back to the 2.0 versions identified in article 1 fixed this.
Would you know why this would be? Just asking.
BTW, I am really enjoying your article. Good information. I also really appreciate all the referenced links and articles. You are doing a fantastic job. It’s good to be able to follow the tutorial and also have references to more detailed information on Identity 2.0 and OWIN.
thank you so much.
Hi mbeddedsoft,
Even I am facing same problem. Could u plz explain what have u done to solve this. Plz give more info about which package needs to update ?
Great post. By registering client id with Authorization server, and securing the JWT token by signing and encryption, are we acheiving the OpenIDConnect 2.0 specifications. Can you please clarify.
Hi Taiseer,
Many thanks for your article. It is very interesting and helpful for someone like me who’s not a server expert 🙂
I learnt a lot from your article and I’ve done all the steps. But I’ve got an issue that you don’t seem to have, and I don’t know why.
1. I can generate IDs and Secrets, no problem, and also request the token. But the response (containing the token) is not properly formatted. PostMan says there’s no headers, and the characters are unknown. Do you have an idea ?
2. Bonus question : Which function is hit when I call the URL for retrieving the token (localhost:xxxxx/oauth/token) ? I would like to do some debugging for 1., but my breakpoints don’t stop the flow.
Thanks a lot !
Hi Daniel,
For your second question you can put breakpoints in methods “ValidateClientAuthentication” and “GrantResourceOwnerCredentials” in the class which inherits from “OAuthAuthorizationServerProvider”.
For your first one I didn’t really understand it, can you elaborate more please?
Regards,
Taiseer
Hi Taiseer!
thanks very much, it’s best solution for authentication and authorization in web api.
i have some important questions :
1.in step 3 inside “CustomJwtFormat” and step 6 inside “ConfigureOAuthTokenConsumption”, you used static value from app setting for sample, is it true? but in real Project we can’t do that because audience id and audience secret are different for each user… so what should we do?
2.in step 6 inside “ConfigureOAuthTokenConsumption” how can i read JWT tokens that sent clients with their requests?
instead this code :
string audienceId = ConfigurationManager.AppSettings[“as:AudienceId”];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings[“as:AudienceSecret”]);
and how should i check user’s token with the user?
I have implemented this tutorial, but when I secure my WebAPI methods with the AuthorizeAttribute they become unavailable, and nothing actually consumes the Jwt Token. There are no errors or anything, so I’m not sure what I’m missing. I can see that the token is created, it is passed back to Angular, and it is included in subsequent requests from Angular to the WebAPI. I can even write a custom AuthorizeAttribute, and if I break in there I can see that the token is in the header of the request. I’m going crazy trying to figure this out. Can you help me?
Hi Mike,
What do you mean by the become unavailable? You mean Unauthorized?
You need to make sure that issuer and audience id are exactly the same in Resource API, use JWT.IO to check your JWT token and inspect the claims inside it.
Hope this will help.
Sorry I should have been more clear…
The JWT token is present in the request, but no ClaimsIdentity is created (that I can so), and just overall I can’t find any information about the user context based on what was in the JWT token. The one thing I did differently from your tutorial was to skip all the stuff with the UserManager, since I have a previously existing user database that I’m hooking into, so I wonder if that’s part of the problem, but it didn’t seem like it should be.
I did wonder if it was because the issuer and audience IDs weren’t the same, but they are. I checked using JWT.IO and I even made them string constants in the code, and the code that issues uses the same constants as the code that calls UseJwtBearerAuthentication.
I figured out what I was doing wrong. I put app.UseWebApi(config) at the top of the Startup code instead of the bottom. So it was sending me to WebAPI before the authorization modules were ever getting called. I asked the question a little better over at the ASP.NET forums and got an answer:
http://forums.asp.net/p/2070482/5976299.aspx?p=True&t=635803483826595456
Thank you so much for the wonderful article.
I created two separate API projects for AS & RS.
Token created from AS is perfectly working as excepted in RS.
But when I use the same token in AS, it goes to Unprotect(string protectedText)
I saw the first comment with same case, but I updated Microsoft.Owin.Security.Jwt 3.0.1.0
AS having other Controllers without Authorize and I am able to get result from those.
If I use Authorize Bearer in AS – it goes to Unprotect method.
Here is my CustomJwtFormat class:
public class CustomJwtFormat : ISecureDataFormat
{
private readonly string _issuer = string.Empty;
private const string AudiencePropertyKey = “audience”;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException(“data”);
}
string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;
if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException(“AuthenticationTicket.Properties does not include audience”);
Audience audience = AudienceManager.FindAudience(audienceId);
string symmetricKeyAsBase64 = audience.Base64Secret;
//var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var keyByteArray = Convert.FromBase64String(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
Here is my Startup class:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuthTokenConsumption(app);
ConfigureOAuthTokenGeneration(app);
//I tried changing the above order
//WebApiConfig.Register(httpConfig);
ConfigureWebApi(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
UnityConfig.RegisterComponents(config);
TeamManagement.WebApi.App_Start.AutoMapperConfig.RegisterMaps();
}
Can you please help where am doing mistake?
Finally found!!!
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext(ApplicationUserManager.Create);
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new Microsoft.Owin.PathString(“/oauth/token”),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(6),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat(“http://localhost:50658”)
};
//app.UseOAuthBearerTokens(oAuthServerOptions);
app.UseOAuthAuthorizationServer(oAuthServerOptions);
}
The commented line was the problem. Sorry, it was my fault but that made me to learn more!!!
Thanks a bunch 🙂
You are welcome, glad you find the issue.
We register allowed Audiences on Startup in both AS & RS.
When client ids are stored in DB, how do RS & AS know about newly registered client ids? – Do we need to restart the app just to get latest added audiences? Is there any better way to do?
I just think, but don’t know good or bad:
Can we use ConcurrentList along with Audience DB, I mean when new Audience added, we should add in both Audience store and ConcurrentList and when IIS refresh then on Startup class, all exists Audiences in ConcurrentList again.
Am not sure – it just an idea…
Taiseer, what a great blog, bravo! It helped me a lot coming into world of web development. One suggestion…
I recently stumbled upon trying to figure out if I want to implement refresh token and carry the burden of extra complexity. I needed a way to easily disable the account to prevent user from using their token from making further requests against the api.
I have modified ConfigureOAuthTokenConsumption(). Setting JwtBearerAuthenticationOptions.Provider to a custom provider, you can override OAuthBearerAuthenticationProvider.ValidateIdentity. You can at this point use the user GUID form incomming token to load the actual identity from database and pass it to context.Validated(identity), this gives you ability to always load fresh credentials with every request.
You can add a flag to check if user is active (requires extra column in database to keep track of active users) this way.
Hi Denyes,
The draw back of this approach is hitting the database with each request to validate user identity, well.. this somehow breaks the stateless nature of the bearer tokens, but if you are fine with this you can do it for sure.
Hi Taiseer
First of all, thank you for this articles. They have helped me to understand OAuth Authentication.
I followed the steps and I don’t see errors when I build the project also runs without exceptions, but when I test and I try to obtain the JWT Token, PostMan shows me an error:
“Invalid object name ‘IdentityUserClaims’
This is throwing when the following line is executed:
User user = await userManager.FindAsync(context.UserName, context.Password);
In my BD already have the table AspNetUserClaim but I’ve not be able to find out the root of the problem.
Could you please advise me or point me to the right direction?
Thanks in advance.
You are welcome Manuel.
Did you try to create your own UserStore and RoleStore, or did you try to configure Asp.Net identity database tables?
Sorry for the late response, and yes, the problem was a misspelling in the table names (dang!)
Hey Taiseer, I just wanted to thank you for your thorough tutorials after combining many of your tutorials I finally created my own middleware. Your tutorials are by far the best I’ve seen. Keep up the good work. Thanks.
Always happy to help, thanks for your comment 🙂
Hi Taiseer, This has been a great tutorial, I have my own angular front end in development against it. Unfortunately tonight the /oauth/token path has started giving me a 404, I’ve rolled back several commits to see if I bonked something along the way and no luck.
Is there a way I can verify that the /oauth/token route is being created/bound correctly? Do you have any other suggestions or things I can check? Thank you in advance.
Hi John,
Giving 404 suddenly means there is change happened on your Angular UI project, I recommend you to use postman to test the back-end and then you can fire fiddler and monitor the requests sent to the Api and see if the URL is correct.
Hi Taiseer,
Thanks for the article. It has helped me a lot on using oauth and JWT. The solution works flawlessly in IIS express, but deploying to IIS 8.5 I get 404 error on http:/localhost/oauth/token. Searching for answer, I’ve updated web.config with all the settings that I found in replies on Stackoverflow. could you please reflect how you host this solution in IIS?
Thanks,
Reza
Hi Reza, that is strange, currently I’m hosting on Azure Web Apps, I assume they are using latest IIS version.
Hi Taiseer,
Thanks for the reply. It was my silliness which I found I had ensured in release mode build, AllowInsecureHttp was set to false.
Thanks,
Reza
Hi Taiseer,
Thank you for uploading above tutorial, Can you please tell me how can I add api version in token signature. I cant figure out this.Thank you very much again learned lot from this article.
{
access token:
token Type:
expires in:
Version:
}
Regards,
Sam.
Hi Sam, if you want to return something in the response of the token endpoint then you can check my SO answer here.
Yesterday I found the same but didnt notice it also from you. Thank you much sharing your knowledge.
Hi Taiseer,
I am posting this in the blog for Part 3 because this is where I’m getting stuck. At the end of Step 4, you direct us to test the ability to start issuing JWT access tokens, by issuing an HTTP POST request to http://localhost:nnnnn/oauth/token with the x-www-form-urlencoded data shown in your diagram. I am using Fiddler as my proxy. The POST request looks like this:
POST http://localhost:55383/oauth/token HTTP/1.1
User-Agent: Fiddler
Host: localhost:55383
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
grant_type=password&username=SuperPowerUser&password=MySuperP%40ss!
I am consistently getting this response:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 87
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: *
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcc3BpZXJzb24uQUdFUlBPSU5UXERvY3VtZW50c1xXZWIgQVBJXEFzcE5ldElkZW50aXR5XEFzcE5ldElkZW50aXR5LldlYkFwaVxvYXV0aFx0b2tlbg==?=
X-Powered-By: ASP.NET
Date: Tue, 17 Nov 2015 16:28:34 GMT
{“error”:”invalid_grant”,”error_description”:”The user name or password is incorrect.”}
I found that the reason for this response is because in the CustomOAuthProvider class that was added in Step 1, in the GrantResourceOwnerCredentials method, the call to userManager.FindAsync always returns a null user object. Therefore, the call to context.SetError is always called, and the 400 response is always issued. I tried single-stepping into the userManager.FindAsync method, but to no avail. I know where it’s breaking, but have no idea as to why. Is there something that I’m overlooking here? Could you please advise me or point me in the right direction? I would greatly appreciate it. Thanks in advance.
Hi,
It is basically not matching username/password from the database with what you are trying to send, you can hard-code username/password, test and you should get an access token. So your issue with validating username/password.
Make sure that password is encoded/decoded correctly before sending it to the password manager.
{
“access_token”: “JWT_Token”,
“token_type”: “bearer”,
“expires_in”: 1799,
“refresh_token”: “8369ac755bdc4e3fa9d3f5870b3af2a0”,
“as:client_id”: “10b7c34b2c184d86aa716ecd7a82acb4”,
“userName”: “testUser”,
“.issued”: “Wed, 18 Nov 2015 06:23:04 GMT”,
“.expires”: “Wed, 18 Nov 2015 06:53:04 GMT”
}
Can I replace with the following Json result:
{
“returnCode”: 200,
“message”: “Custom Message”,
“data”: {
“access_token”: “JWT_Token”,
“token_type”: “bearer”,
“expires_in”: 1799,
“refresh_token”: “8369ac755bdc4e3fa9d3f5870b3af2a0”,
“as:client_id”: “10b7c34b2c184d86aa716ecd7a82acb4”,
“userName”: “testUser”,
“.issued”: “Wed, 18 Nov 2015 06:23:04 GMT”,
“.expires”: “Wed, 18 Nov 2015 06:53:04 GMT”
}
}
If you want to change the response you can do this, its up to you
I mean there is no easy way to change response json format, unless intercept and modify OWIN Body Response Stream. Right?
Thank you for this tutorial, I now have a working security model for my WEB API, I am creating.
One question though: If IIS is reset, will all outstanding JWTs still work or will they need to be reissued?
Sure thing, all JWT issues will be working, those are self contained tokens and IIS has nothing to do with them
Great series! They are really helpfull! But I’m kinda stuck at the moment.
i can get the access_token from the token endpoint, no problem. but when I try to use the token to reach one of my controller actions with an {Authorize] attribute I get 401.
My get request looks as follows:
url: http://localhost:51388/api/crm/accounts
Headers:
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiI3YjIyN2MyYi0wNmZhLTQ4NmEtYjIyZC0wMWJmODRlMjc4YjIiLCJ1bmlxdWVfbmFtZSI6IkFkbWluIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9hY2Nlc3Njb250cm9sc2VydmljZS8yMDEwLzA3L2NsYWltcy9pZGVudGl0eXByb3ZpZGVyIjoiQVNQLk5FVCBJZGVudGl0eSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiZTA5NDA4ZjktM2I3MS00NGI0LTkyNDMtNmM3MWMwY2E3ZGI0Iiwicm9sZSI6IkFkbWluaXN0cmF0b3IiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUxMzg4LyIsImF1ZCI6IjQxNGUxOTI3YTM4ODRmNjhhYmM3OWY3MjgzODM3ZmQxIiwiZXhwIjoxNDUwNzc5ODcwLCJuYmYiOjE0NTA2OTM0NzB9.mbcByoYt2STkwfrJsWJyJ35PUE2-4kis-UAy9RU-KBs
and my controller looks like this:
[HttpGet]
[Route(“”)]
[Authorize]
public IHttpActionResult Accounts()
{
var accounts = _uow.Repository().GetAll(a => a.ParentAccountId == null, “Addresses”, “PhoneNumbers”, “EmailAddresses”);
var accountDtos = Mapper.Map<IEnumerable, List>(accounts);
return Ok(accountDtos);
}
I don’t really know where to start looking to find out why it keeps giving me te 401. I have compared the example code and my code a couple of times, but it looks good te me. Any ideas on where to look?
Please check this comment which might help in debugging your issue
I first want to thank Taiseer for this excellent set of tutorials. I’ve walked through this and the one on creating a Token server and I’ve found both to be well-written and a great primer into owin middleware and tokens. If you are having problems with 401s, you can read the story, or jump to my solution!
The first time I walked through this set of blogs I was up and running and moved on to other tasks. I then tried to implement it from memory and was not able to validate endpoints with tokens (401). After going line by line through my code and nuget versions I did not find a difference from my working example.
So, I created another one that was far simpler, removing everything not directly related to webapi2, owin, or tokens, starting from an empty web project. The result, still not able to authenticate tokens with the JwtBearerAuthentication middleware.
This lead me down the rabbit hole of owin middlewares, how they function, are built, etc. Nothing I tried, and I everything the internet could suggest worked for me.
I eventually learned how to build my TokenHandler, deriving from JWTSecurityTokenHandler. Overriding that gave me great insight into how OWIN processes and validates tokens.
I discovered that the ValidateToken function was throwing exceptions, which leads to the token to be considered not valid. The obvious reasons for an invalid token:issuer, audience, keys not matching, were all triple-checked and confirmed to be the same on both ends. So why and where was an exception being raised?
The culprit ended up being the ValidateAudience method. First, I was surprised this was a method and not a function, but I am sure there is a valid reason for this! I do not know why it was failing, but I ended up calling the base method from my overridden ValidateToken function with the code that follows. Result? Success! So two days of banging my head against the OWIN wall I am ready to move on again, with a much greater appreciation/frustration for MS’s implementation of middleware.
public override ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
var jwt = this.ValidateSignature(securityToken, validationParameters);
if (validationParameters.ValidateAudience)
{
if (validationParameters.AudienceValidator != null)
{
if (!validationParameters.AudienceValidator(jwt.Audiences, jwt, validationParameters))
{
throw new SecurityTokenInvalidAudienceException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10231, jwt.ToString()));
}
}
else
{
base.ValidateAudience(validationParameters.ValidAudiences, jwt, validationParameters);
}
}
string issuer = jwt.Issuer;
if (validationParameters.ValidateIssuer)
{
if (validationParameters.IssuerValidator != null)
{
issuer = validationParameters.IssuerValidator(issuer, jwt, validationParameters);
}
else
{
issuer = ValidateIssuer(issuer, jwt, validationParameters);
}
}
if (validationParameters.ValidateActor && !string.IsNullOrWhiteSpace(jwt.Actor))
{
SecurityToken actor = null;
ValidateToken(jwt.Actor, validationParameters, out actor);
}
ClaimsIdentity identity = this.CreateClaimsIdentity(jwt, issuer, validationParameters);
if (validationParameters.SaveSigninToken)
{
identity.BootstrapContext = new BootstrapContext(securityToken);
}
validatedToken = jwt;
return new ClaimsPrincipal(identity);
}
Thanks for sharing this, really appreciated, I never digged too deep in the implementation of the JWTTokenSecurityHandler. I just replied on your SO comment but things are clear now. Thanks again for sharing this.
Good evening, I’m going through the same problem and also to days.
I’m sorry for my basic English.
I followed his comment but did not understand where I add these lines of code. Which of the classes created in the tutorial I add them? I create new classes?
I await their return and since I thank you for your attention.
Thanks,
Rafael de Oliveira.
Hi
Great tutorial. I do just have one problem. When I login I get the token but when I try to pass the token to changepassword api then I get a 401. It is like it doesn’t even try to validate the token?
I have made a stackoverflow ticket on it: https://stackoverflow.com/questions/34405490/web-api-giving-401-on-jwt
Hope you can help.
Hi,
Is this happening only for this endpoint or you are receiving 401 on other endpoints attribute with [Authorize] attribute?
I’ve posted a potential solution over on StackOverflow and otherplaces on this Blog, but you basically want to create your own JWTTokenHandler that derives from JWTSecuirityTokenHandler. This will at least let you ‘open the hood’ and see why your token is failing Authorization.
I think I figured out what the problem is… issued should be in local time and not in UTC. I put a longer reply with code snippets in the same StackOverflow post.
Hey Taiseer, I was wondering if you’ll be offering a write up for ASP NET 5? Your walkthrough has worked flawlessly for us in our older project. I’m currently trying to implement it but I’ve notice quite a bit has changed. thanks again for all your hard work!
Hi Chris,
I’m just waiting for RC 2 as the ASP.NET team keeps breaking some methods which each release, as well the Identity and token issue still not clear in ASP.NET 5 yet, there is no built in middleware to issue access token in ASP.NET 5. Maybe I will use the external IdSrv3 or Open Id connection middleware to do this task.
Excellent explanation and it works fine. One issue here is that when the token is invalid or not specified I’m getting 404 (NotFound) instead of 401 (NotAuthorized). I configured my OAuth exactly like you described here. What could be wrong?
Hi Alex, sorry for the late reply.
Did you find solution for your issue? I never faced such issue when the API returns 404 when it is unauthorized.
I have noticed that if I also getting redirect to Login.aspx even though I disabled forms auth in web.config.
It seems that after publishing to azure forms auth module continue to work. I found similar issue here and as one of solution is to remove that module:
http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx/
Hey Taiseer, I am making a call web api in order to authenticate users from asp.net application
private static async Task GetAPIToken(string userName, string password, string apiBaseUri)
{
using (var client = new HttpClient())
{
//setup client
client.BaseAddress = new Uri(apiBaseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
//setup login data
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair(“grant_type”, “password”),
new KeyValuePair(“username”, userName),
new KeyValuePair(“password”, password),
});
//send request
HttpResponseMessage responseMessage = await client.PostAsync(“/Token”, formContent);
//get access token from response body
var responseJson = await responseMessage.Content.ReadAsStringAsync();
var jObject = JObject.Parse(responseJson);
return jObject.GetValue(“access_token”).ToString();
}
}
The PostAsync is executed successfully on the web api but I could not get the response message in my web application.
Any ideas ?
Thanks in advance,
Leo
@Leo did You manage to solve this? I need to do something similar. Thanks for reply.
Hi Taiseer
Again, thanks a lot for this tutorial but I’m a little bit confused and I hope you could help me.
In a real-life situation, should I validate my client app in ValidateClientAuthentication method inside CustomOAuthProvider class? or it is enough with the AudienceId and AudienceSecret or I’m totally confused?.
In addition, Audience ID could be any string (e.g. ‘My App’) just with HMAC265, same for the Audience secret?.
Drop this into a windows form with a button and a textbox for the result…
using System;
using System.Windows.Forms;
using Microsoft.Owin.Security.DataHandler.Encoder;
using System.Security.Cryptography;
namespace GenSecret
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
var clientId = Guid.NewGuid().ToString(“N”);
var key = new byte[32];
RNGCryptoServiceProvider.Create().GetBytes(key);
var base64Secret = TextEncodings.Base64Url.Encode(key);
textBox2.Text = string.Format(“Client Id: {0}\r\n\r\nSecret: {1}”, clientId, base64Secret);
}
}
}
Help Need. The system works well with create user, delete user, list all the users. however, it fail to obtain token. even i supplied the right username and password, it continue give me error message invalid_grant. I use debugger to trace, and found ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password); return a Null value.
Exception:Caught: “Could not load file or assembly ‘Microsoft.VisualStudio.Web.PageInspector.Runtime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The system cannot find the file specified.” (System.IO.FileNotFoundException)
A System.IO.FileNotFoundException was caught: “Could not load file or assembly ‘Microsoft.VisualStudio.Web.PageInspector.Runtime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The system cannot find the file specified.”
Time: 14/02/2016 10:50:51 PM
Thread:[28136]
Any Idea what could be wrong?
Maybe this answer will help you
This is the best tutorial that I can found. I have a error in the last step, it says: JwtSecurityTokenHandler.cs not found. Do I need to create this class? Thanks for your help.
Download the source code from GitHub and check if this class is created or from NuGet package.
calling time –> http://localhost:59822/oauth/token
actionfilter , DelegatingHandler not working
Hi,
I tried your solution on azure and it works perfectly. However when I try your solution on another server I get the notification below. It only happens on the first login attempt. The second, right after the first, works perfectly. Any idea on what could be causing this?
XMLHttpRequest cannot load https://api-address/oauth/token. Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘https://client-address’ is therefore not allowed access. The response had HTTP status code 400.
I’m not sure why this is happening, but I recall I faced the same issue and we discussed it on the comments section for this post. Can you please check this answer
This is exactly the solution which helped me. Unfortunately I found it out myself yesterday. After I placed the usecors on top an error in my application log started to arise regarding duplicate ‘Access-Control-Allow-Origin’. After removing the line in the article you send it disappeared. Thanks for your reply though 🙂
Hi
This is an excellent article.
here is one issue I am facing , in the GrantResourceOwnerCredentials if the user is not found either because of wrong username or password , A set error method is called
if (user == null)
{
context.SetError(“invalid_grant”, “The user name or password is incorrect.”);
return;
}
In the above situation the HttpStatus code is always set to 400 (bad request) . I have tried various approaches but could not set the HttpStatus code to 401. Do you know if there is a way to do it ? I have been struggling with this for some time now.
Hi Amol,
Returning 400 is the correct http status in this case, and this based OAuth 2.0 specs, the user is not authenticated yet and he is providing incorrect username/password so he he is providing incorrect data from the client, so 400 is correct. You should return 401 if the user was already authenticated (has an access token) and this token is expired or invalid anymore.
Hi.
Thank you for these posts, they make a very difficult subject comprehensible.
However I am still a bit confused in what the difference is between the tutorial here on this page, where we are issuing
JWT tokens with oauth insted of “default access tokens” and the tutorial in this 5 part series where we are issuing “OAuth Bearer Tokens”:
https://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
As I understand both these tokens are fully self-contained, and there is no corresponding session on the server for any of them, so what is actually the practical difference between issuing and using these two type of tokens?
Is it just that you can decouple Authorization server from Resource server with JWT?
Thanks!
Hi Ole,
The tutorial here is using Bearer tokens as the post here too, the difference only relies on the access token format, the JWT tokens are signed only (not encrypted) and you can decode the claims in the client side application, you can use JWT.io to decode the JWT and see the claims, on the other side, the JWT format is becoming the more standard way of sending OAuth 2.0 bearer tokens.
Hope this answers your question.
I echo all the thanks, these tutorials are a little bit vital !
I (too) am mystified when you say the Angular front end is a “trusted client”. How is it trusted? How is it even identified (authenticated)?
Thank you for your reply. I just have one more questions.
I want to add login and registration with external provider (facebook, google) to the application.
Can I use the guide you have provided here (https://bitoftech.net/2014/08/11/asp-net-web-api-2-external-logins-social-logins-facebook-google-angularjs-app/) as-is, or do I have to make some changes to that code now that I have configured the app to use JWT ?
Thanks.
To answer my own question: The guide on implementing facebook/google login can be used pretty much as-is if you have followed the guide on this page to issue and consume json web tokens, but some small changes was required. Here is what I changed:
In the first guide you set OAuthBearerAuthenticationOptions as a static member of Owin Startup class and later call
app.UseOAuthBearerAuthentication(OAuthBearerOptions) as shown in the code here: https://github.com/tjoudeh/AngularJSAuthentication/blob/master/AngularJSAuthentication.API/Startup.cs#l54
Skip that part. Instead you set OAuthAuthorizationServerOptions as a static member of Startup class, then you just follow the guide on this page (initialize it and call app.UseOAuthAuthorizationServer(OAuthServerOptions) ). You also have to call
“app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);” as explained in the first guide. https://github.com/tjoudeh/AngularJSAuthentication/blob/master/AngularJSAuthentication.API/Startup.cs#l40
Then you can generate a similar JWT as in path ”http://localhost:59822/oauth/token” in method GenerateLocalAccessTokenResponse in AccountController.
here is my code:
At the end In method “RegisterExternal” and “ObtainLocalAccessToken”:
[…]
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager, “JWT”);
var accessTokenResponse = GenerateLocalAccessTokenResponse(oAuthIdentity);
return Ok(accessTokenResponse);
private JObject GenerateLocalAccessTokenResponse(ClaimsIdentity oAuthIdentity) {
TimeSpan tokenExpiration = TimeSpan.FromMinutes(Convert.ToDouble(ConfigurationManager.AppSettings[“JWTExpirationTimeInMinutes”]));
var props = new AuthenticationProperties() {
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.Add(tokenExpiration),
};
var ticket = new AuthenticationTicket(oAuthIdentity, props);
var accessToken = Startup.OAuthServerOptions.AccessTokenFormat.Protect(ticket);
JObject tokenResponse = new JObject(
new JProperty(“access_token”, accessToken),
new JProperty(“expires_in”, tokenExpiration.TotalSeconds.ToString()),
new JProperty(“token_type”, “bearer”));
return tokenResponse;
}
Thanks again to Taiseer Joudeh for these guides!
You are most welcome, and thanks for sharing the answer and your thoughts.
This is a great article. I understand that we are leveraging the default [Authorize] Attribute. I want to create a custom Authorize Attribute with custom logic to deal with my authentication. When I create one I am noticing that the app.UseJwtBearerAuthentication does not execute and I can pass in invalid json web tokens. Is there a way to configure UseJwtBearerAuthentication to use a custom authorize attribute after it is done validating the token?
Thanks
@Taiseer again great article. I’m still learning new things from whole serie. I got use case that I’m trying to solve, but for now I’m stuck.
I’m creating new user using CreateUser method, but instead new user object I’d like to return JWT token. Idea is to remove that extra call that is required to sign-in. In other words I’d like to return token so when user account is created he can already do API calls without need to sign-in.
Can this be done? I found some code by @Leo (https://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/comment-page-2/#comment-73830) but it requires creating HttpClient and I’d like to avoid that.
Hi Tomasz,
I got your question, you need to register a user then directly generate a token without doing a login, so what you trying to achive is to generate a token inside a controller, please check this SO answer, it might be useful.
Hi Taiseer
Great series, I’ve used your tutorials to setup jwt oauth flows for many projects.
Recently I’ve been concerned about storing token data in browser local storage and I’m trying to instead keep the jwt token encrypted in an http only cookie (for the web clients)
Is there a natural extension to the approach you’ve discussed whereby I can both store the token in an httponly cookie and handle the refresh token flow without the client explicitly making a call to refresh?
Thanks
Graeme
Hi Graeme,
You can check the ThinkTecture Identity where they have helpers to do this, I didn’t try this but I remember I watched Brock doing a demo while he was able to refresh tokens using Identity Model.
Hope this helps.
Hi Taiseer,
Wonderful articles on Oauth. I want to implement OAuth 2.0 using MAC token and not Bearer token as I am interested to use SSL along with OAuth. Can you please guide me to implement the same.
Thanks,
Mady
Hi Taiseer,
I downloaded the source code you posted and then, using Visual Studio 2015, I opened the solution. It built just fine, but when I run it:
1) The Configuration method of the Startup class is never called;
2) Any attempt (with Postman) to get a token at http://localhost:59822/auth/token results in a 404 error.
Can you advise on how I can figure out what the problem is?
Thanks so much!
Hi Taiseer,
I’m still not sure why your solution is not working correctly in my local environment, but I have implemented the key portions in my primary test project, which is working, so please don’t spend any time working on it.
Thanks for everything – your articles are great!
— John
You are welcome and sorry for the late reply 🙂
Hi Taiseer,
Is it possible to use only OAuth security without Asp.Net identity or OWIN but my own membership functionality???
Sure thing, you can use it with any DB provider you want, not only SQL. ASP.NET Identity for managing users and has nothing to do with OAuth security.
I have read your posts and they are great. I have tried implementing this in my own application and when I come to use Postman to the oauth/token endpoint I am getting the same error every time:
{
“error”: “invalid_client”
}
Can you think of any reason why I would be getting this?
Also, the audienceId and audienceSecret have me confused. I looked at the way you were generating them and it looks like the secret is just base64 encoded id, is that correct?
Hi,
The articles are excellent. Thank you very much for all your effort.
I have been scratching my head on this one….. I downloaded your project from Git and compiled it ok. I run and test the oauth/token endpoint and my context within this method is always null for the username and password in the context. Have you seen this before?
File: AspNetIdentity.WebApi.Providers.CustomOAuthProvider
Method: GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
Line: ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
Issue: context.UserName and context.Password are null
Kind regards
Dan
Hi Dan,
You need to make sure your sending the request using the correct content-type, it should not be JSON, it should be “x-www-form-urlencoded”
Hope it helps.
Hi,
thanks for the reply. This is what I was wondering however I have double checked and know (believe) that I am passing the correct content-type.
Please see request below from fiddler.
POST http://localhost:52212/oauth/token HTTP/1.1
Host: localhost:52212
User-Agent: Mozilla/5.0 (Windows NT 6.2; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Authorization: Basic dGVzdEB0ZXN0LmNvbTp0ZXN0MjM0ISI=
Content-Length: 19
Connection: keep-alive
grant_type=password
It is really weird. Not sure why this is as I cannot seem to obtain any relevant information as to why the context has nulls in it.
Any other suggestions? Would it be that I have updated the assemblies due to nuget update?
Kind regards
Dan
I have an Android App talking to an ASP.NET Web API back-end. Android app offers SignIn with email address or SignIn with Google.
I am using Google’s SDK for rich SignIn experience i.e. user doesn’t need to provide credentials and directly opens rich dialog for authorization. I am able to get the access token and user profile. So far so good.
Coming to ASP.NET Web API external authentication. I understand that once I have access token, most likely the following needs to happen:
Android app calls Web API with Access Token to do ExternalSignIn
Web API processes the request and returns bearer token of SignedIn user.
validates access token
obtains user’s login info from Google
check for existing local user. If not found, create one.
Generate bearer token for the local user (newly created or existing one)
Return it to the caller
Web API can now use bearer token to call protected APIs.
I have been studying OWIN Auth Server and all the auth/authz code that ASP.NET creates for external social accounts, it seems it is assuming app will use web flow for Google Sign-In and there will be auth cookie set by the Google OWIN middleware.
I have searched a lot, but couldn’t find any good pointers on how to do it efficiently by using ASP.NET’s built-in support for Google sign in.
Worst case, the alternative that I have in my mind is:
Create a Web API ExternalSignIn(string accessToken)
In the Web API, pretty much do what I mentioned above.
I have an Android App talking to an ASP.NET Web API back-end. Android app offers SignIn with email address or SignIn with Google.
I am using Google’s SDK for rich SignIn experience i.e. user doesn’t need to provide credentials and directly opens rich dialog for authorization. I am able to get the access token and user profile. So far so good.
Coming to ASP.NET Web API external authentication. I understand that once I have access token, most likely the following needs to happen:
1. Android app calls Web API with Access Token to do ExternalSignIn
2. Web API processes the request and returns bearer token of SignedIn user.
2.1 validates access token
2.2 obtains user’s login info from Google
2.3 check for existing local user. If not found, create one.
2.4 Generate bearer token for the local user (newly created or existing one)
2.5 Return it to the caller
3. Web API can now use bearer token to call protected APIs.
I have been studying OWIN Auth Server and all the auth/authz code that ASP.NET creates for external social accounts, it seems it is assuming app will use web flow for Google Sign-In and there will be auth cookie set by the Google OWIN middleware.
I have searched a lot, but couldn’t find any good pointers on how to do it efficiently by using ASP.NET’s built-in support for Google sign in.
Worst case, the alternative that I have in my mind is to create a web api that does external sign in with access tokens by doing the above 1-3.