Bit of Technology

  • Archive
  • About Me
    • Advertise
    • Disclaimer
  • Speaking
  • Contact

Implement OAuth JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 – Part 3

February 16, 2015 By Taiseer Joudeh 339 Comments

Share this:

  • Twitter
  • LinkedIn
  • Reddit
  • Facebook
  • Email

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

Featured Image

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:

C#
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:

C#
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:

MS DOS
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:

C#
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:

C#
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:

C#
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.

JSON Web Token

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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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”

Request JWT 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.

Change Password Web API

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

Share this:

  • Twitter
  • LinkedIn
  • Reddit
  • Facebook
  • Email

Like this:

Like Loading...

Related Posts

  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4
  • AngularJS Authentication Using Azure Active Directory Authentication Library (ADAL)
  • JSON Web Token in ASP.NET Web API 2 using Owin
  • Decouple OWIN Authorization Server from Resource Server

Filed Under: ASP.NET, ASP.NET Identity, ASP.Net Web API, CodeProject, Web API Security, Web API Tutorial Tagged With: Authentication, Authorization, JSON Web Tokens, JWT, OAuth

Comments

  1. Abhijit Ajmera says

    June 28, 2016 at 10:30 am

    Getting this error while posting my question.

    Notice: Trying to get property of non-object in /home3/bitoftec/public_html/wp-content/plugins/crayon-syntax-highlighter/crayon_wp.class.php on line 717

    Warning: Cannot modify header information – headers already sent by (output started at /home3/bitoftec/public_html/wp-content/plugins/crayon-syntax-highlighter/crayon_wp.class.php:717) in /home3/bitoftec/public_html/wp-includes/comment.php on line 517

    Reply
  2. Elizabet An says

    July 8, 2016 at 10:00 pm

    The CustomJwtFormat breaks when targeting .NET 4.6.1 and update all my packages:
    “The type or namespace name ‘JwtSecurityToken’ could not be found (are you missing a using directive or an assembly reference?)”

    These are the references I have for that class:
    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.DataHandler.Encoder;
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.IdentityModel.Tokens;
    using System.Linq;
    using System.Web;
    using Thinktecture.IdentityModel.Tokens;

    Any idea how to make it work for 4.6.1?

    Reply
    • Taiseer Joudeh says

      July 10, 2016 at 10:49 am

      Hi Elizabet,

      Well, I didn’t try to upgrade to .NET 4.6.1 framework. But is there a certain package which is not compatible with the 4.6.1? I will try to take a look at it and if you find a solution please share it here.

      Reply
      • David says

        July 21, 2016 at 7:25 pm

        Hi Taiseer,

        I am having the same issue “The type or namespace name ‘JwtSecurityToken’ could not be found “. Any thoughts? Thank you.

        Reply
        • Phil Huhn says

          December 29, 2017 at 11:30 pm

          I resolved it by changing the using statement to
          using System.IdentityModel.Tokens.Jwt;

          Reply
    • Jake says

      September 29, 2016 at 1:02 pm

      Has this been resolved?

      Reply
  3. David Gravitas says

    July 21, 2016 at 6:44 am

    Thank you so much for taking the time to share your knowledge! This article has helped me out a great deal in understanding OAuth and tokens. I am confused on how to properly generate the client_id and the client_secret. You provided a link to source code when talking about the client_id and the client_secret. Is this code used to generate these values? Thank you!

    Reply
    • Taiseer Joudeh says

      July 24, 2016 at 1:06 pm

      Hello David,
      You can find the code used to generate the clientid and secret in the Seed method for EntityFramework Configuration class.

      Reply
      • Terry Harrison says

        August 4, 2016 at 10:06 pm

        I am confused by this answer. Your link for the implementation above pointed to a class named AudiencesStore. Is this supposed to be added to the project?

        Reply
        • Christophe Hvd says

          October 18, 2016 at 7:25 pm

          Same question here, I don’t understand how to generate the Audience id and secret.
          Concerning the implementation file you provided (AudienceStore.cs), shall we create a console app next to this project and use it to generate Audience id/secret ?

          Reply
          • nicky says

            May 26, 2017 at 8:52 pm

            Hi Christophe,
            I allow myself to answer instead of Taiseer. I’ve used the whole solution with success and I confirm, that’s what I did (create a console app) to generate the Audiences id/secret

            By the way, thanks a bunch Taiseer for your incredibly helpful work 😉

          • Taiseer Joudeh says

            June 13, 2017 at 12:53 am

            You are right Nicky, I used a test project to generate this, sorry for not being clear describing this step.

    • Torsten Tiedt says

      November 10, 2016 at 9:26 pm

      Hi,

      using Taiseer’s suggested AudienceStore class I wrote a simple unit test to get the desired audience id and secret:

      [TestClass]
      public class AudienceStoreTest
      {
      [TestMethod]
      public void WhenGeneratingClientIdAndClientSecretTheyAreGenerated()
      {
      var audience = AudiencesStore.AddAudience(“ANY_NAME_YOU_WANT”);
      }
      }

      I set a break point at the end of the unit test and used the watch window to copy-paste the required data.

      Of cource, I added his class and a helper class “Audience” into my project.

      Hope this is correct and helps,

      Torsten

      Reply
      • Phil Huhn says

        January 7, 2018 at 10:58 pm

        Get AudiencesStore and Audience class from here:
        https://github.com/tjoudeh/JWTAspNetWebApi/tree/master/AuthorizationServer.Api

        Reply
  4. NIco says

    August 17, 2016 at 11:47 am

    Get an “unsupported_grant_type” error when posting to “http://localhost:58604/oauth/token” as demonstrated?

    Reply
    • Taiseer Joudeh says

      August 21, 2016 at 12:03 pm

      You are facing the same issue if you cloned the GitHub code?

      Reply
      • Christian Sanabria says

        September 12, 2016 at 10:40 pm

        I am!!!

        Reply
      • Abhay Shiro says

        January 24, 2017 at 8:38 am

        Assalam Walaykum, Taiseer.

        Thanks a lot for this great tutorial.

        About the invalid grant type, content type should be application/x-www-form-urlencoded , type of request should be POST and in Raw Payload enter grant_type=password&password=PASSWORD&username=USERNAME

        This I tried on ARC. This request works fine.

        Reply
        • Jan says

          February 2, 2017 at 7:01 pm

          Thanks!
          Apparently Postman doesn’t clear the Raw field when changing the radio to form-data, therefore the body sent (still the Raw) is wrong and the grant_type isn’t known.

          Reply
      • HuangZhongqiu says

        July 21, 2017 at 5:55 am

        Hi, thank you for your tutorial first. I have a question.
        There are username and password is display in the url parameters and how can we Protected user info?
        Looking forward to your answer.

        Reply
    • Todd says

      September 20, 2016 at 6:36 am

      What worked for me on this:

      Make sure you’re putting the username/password/grant_type in the “Body” tab of PostMan. First, check the radio button for x-www-form-urlencoded and then enter the info in the below fields right below the radio button… It looks identical to the “Headers” section, but it’s not.

      Reply
  5. Taieb Zayed says

    August 20, 2016 at 9:31 am

    I have followed your full tutorial, but at this point the authorization is not working. Any protected endpoint generates
    “Authorization has been denied for this request.” error. I have generated the token and passed it in the authorization key in Header and also Added the bearer key. Can anyone help me?

    Reply
    • Taiseer Joudeh says

      August 21, 2016 at 12:01 pm

      Hello Taieb,

      Can you make sure that you are using the same issuer without any trailing slashes?

      Reply
      • Thiago Neto says

        December 18, 2016 at 8:55 pm

        Muito bom!! Me ajudou!

        Reply
      • Alex says

        January 28, 2017 at 7:25 am

        that was my problem too. Working now.
        Thank you for taking your time and writing these tutorials.

        Reply
      • Pierre Thalamy says

        March 16, 2017 at 6:03 pm

        I was getting the same error and I had not set the issuer variable properly either indeed.
        Thank you Taiseer!

        Reply
    • Lenka says

      September 14, 2016 at 3:12 pm

      Hi Taieb,

      I had the same problem. It was my mistake – My localhost app was running on different port and i forgot change it for issuer in Startup.ConfigureOAuthTokenConsumption(IAppBuilder app) method.

      @Taiseer: Thank You very very much for this tutorial 🙂

      Reply
      • Taiseer Joudeh says

        September 14, 2016 at 10:50 pm

        You are welcome, happy to help 🙂

        Reply
    • Mike says

      January 6, 2017 at 6:41 pm

      Getting the same error. Checked the issuer and it’s the same.

      Reply
  6. S Sinha says

    September 19, 2016 at 12:41 pm

    Getting this error:
    I am using the same code from Git. I guess I am missing something in Step:3 to generate the AudenceID and AudenceSecret key. Using same code I am able to get users, delete users but not able to reset password.

    Please guide me to.

    {
    “message”: “An error has occurred.”,
    “exceptionMessage”: “UserId not found.”,
    “exceptionType”: “System.InvalidOperationException”,
    “stackTrace”: ” at Microsoft.AspNet.Identity.UserManager2.d__2a.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at AspNetIdentity.WebApi.Controllers.AccountsController.d__5.MoveNext() in C:\\Users\\ssinha01\\Desktop\\MVC\\AspNetIdentity.WebApi-master\\AspNetIdentity.WebApi-master\\AspNetIdentity.WebApi\\Controllers\\AccountsController.cs:line 139\r\n— End of stack trace from previous location where exception was thrown —\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Threading.Tasks.TaskHelpersExtensions.d__3`1.MoveNext()\r\n— End of stack trace from previous location where exception was thrown —\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n— End of stack trace from previous location where exception was thrown —\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n— End of stack trace from previous location where exception was thrown —\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()”
    }

    Reply
    • S Sinha says

      September 19, 2016 at 3:58 pm

      It is resolved now. I missed to call the function ‘ConfigureOAuthTokenConsumption’ from Configuration in Startup.cs file.

      Reply
  7. TJ says

    September 26, 2016 at 5:02 pm

    I am having a lot of trouble following this tutorial because I am not using the versions of the packages that you are using. Like when I am write this line:

    var token = new JwtSecurityToken(issuer, plaintext, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signKey);

    I am getting this error: ‘cannot convert from ThinkTecture.IdentityModel.Tokens.HmacSigningCredentials to Microsoft.IdentityModel.Tokens.SigningCredentials.

    And in your git repo, you are using this namespace using System.IdentityModel.Tokens;
    and my version of Visual Studio is making me using System.IdentityModel.Tokens.Jwt

    And for some reason, I can’t let the type convert.

    Reply
    • TJ says

      September 26, 2016 at 6:44 pm

      okay, so I narrowed down the problem. I am using Version 5.0.xxxxx
      and you are using an earlier version like version 4.0.xxxxx

      The newer version is using different references. So the older version uses
      using System;
      using System.Collections.Generic;
      using System.Collections.ObjectModel;

      The newer version uses
      using Microsoft.IdentityModel.Tokens;
      using System;
      using System.Collections.Generic;

      I narrowed down the problem, but I don’t know where to go from here

      Reply
    • Taiseer Joudeh says

      October 2, 2016 at 1:54 pm

      Hi TJ,
      Sorry for the late reply, I understand your frustration but sometimes NuGet packages for certain libraries tend to introduce breaking compatibilities, the best thing to do is to check the GitHub documentation and release notes for each package and see what has been changed and try to implement in the new version.
      Sorry for not being helpful but I can’t reproduce your issue now.

      Reply
      • Jerome says

        April 5, 2017 at 4:21 pm

        Hi,
        I had the same issue and was able to fix it thanks to that post :
        http://stackoverflow.com/questions/38338580/conflict-between-system-identitymodel-tokens-and-microsoft-identitymodel-tokens

        In the end, in \Providers\CustomJwtFormat.cs , I have (excerpt) :
        using Microsoft.Owin.Security;
        using Microsoft.Owin.Security.DataHandler.Encoder;
        using System;
        using System.Configuration;
        using System.IdentityModel.Tokens;
        using System.IdentityModel.Tokens.Jwt;
        …
        public string Protect(AuthenticationTicket data)
        {
        …
        var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
        var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(keyByteArray);
        var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);

        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, signingCredentials);
        …
        }

        Reply
        • GBusato says

          March 11, 2018 at 12:28 pm

          Thanks for your reply ! I had the same problem !

          Reply
  8. Bhadresh says

    September 29, 2016 at 2:07 pm

    Hello,

    Which Value we need to set For Below Key in Web.config file
    as:AudienceId

    as:AudienceSecret

    Reply
    • Lug Velez Schmitz says

      October 14, 2016 at 5:42 am

      In AudienceId anything (I tried with an empty string), but in AudienceSecret any Sha256, Sha384 or Sha512 signature.

      Reply
      • Brent Coppock says

        October 16, 2016 at 11:30 pm

        Actually, The Sha512 one does not work. The exception is “Invalid Key Length”. I then tried a Sha256 and it worked. I then tried Sha385 out of interest and it also did not work. Same error. Obviously I might have done something wrong / different that yourself (Lug Velez Schmitz) so I leave it open to user error on my part. Just wanted to post here to help others who might get this same error.

        Reply
        • Taiseer Joudeh says

          October 28, 2016 at 3:43 pm

          Thanks Brent for sharing this.

          Reply
  9. Simon says

    September 30, 2016 at 5:01 pm

    Hi!
    Great tutorial.
    Nevertheless I’ve got some issue and asking U for help:
    Argument 6: cannot convert from ‘Thinktecture.IdentityModel.Tokens.HmacSigningCredentials’ to ‘Microsoft.IdentityModel.Tokens.SigningCredentials’
    (I’ve got system.identitymodel.tokens.jwt 5.0.0. installed)

    Reply
    • Taiseer Joudeh says

      October 2, 2016 at 1:45 pm

      Hi Simon, this is due to different NuGet packages with breaking compatibility, unfortunately i do not have enough time to check how to upgrade them, but if you used the same NuGet packages I’m using the tutorial then you are good and you will not face this issue.

      Reply
  10. kittipongint says

    October 20, 2016 at 7:55 am

    Do not use System.IdentityModel.Tokens.Jwt 5.0.0, I have 2 reasons to prevent you from update to version 5.x.

    1. Because there are change in initalizing JwtSecurityToken() object you will get this error : “cannot convert from ThinkTecture.IdentityModel.Tokens.HmacSigningCredentials to Microsoft.IdentityModel.Tokens.SigningCredentials”

    but can fixed with this code [CustomJwtFormat.cs] – work fine, get access_token normally :

    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 securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(keyByteArray);
    var signingKey = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);

    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;
    }

    2. Even if you pass #1 you will face this error : “Could not load type ‘System.IdentityModel.Tokens.TokenValidationParameters’ from assembly ‘System.IdentityModel.Tokens.Jwt, Version=5.0.0.127, Culture=neutral, PublicKeyToken=31bf3856ad364e35” at function app.UseJwtBearerAuthentication() because Microsoft.Owin.Security.Jwt require System.IdentityModel.Tokens.Jwt branch 4.x

    Reply
    • kittipongint says

      October 20, 2016 at 12:19 pm

      Thank you very much, Taiseer Joudeh, This is a great tutorial series and it save my life. Thank you very much again.

      Reply
      • Taiseer Joudeh says

        October 28, 2016 at 3:22 pm

        You are most welcome, happy to help.

        Reply
  11. vinh Le says

    October 26, 2016 at 10:14 am

    Hi Taiseer,

    Once again loving your style of detailed explanation.
    Would you be pointing me to how or will you have another article about revoking an issued JWT token?

    Cheers,
    Vinh

    Reply
    • Taiseer Joudeh says

      October 28, 2016 at 2:59 pm

      Hello Vinh,
      Revoking an issued refresh token is all about deleting it from the DB, you need to delete the identifier for it and that’s it.

      Reply
  12. Marcus Cole says

    November 8, 2016 at 11:21 pm

    Just wanted to add a warning about using “TextEncodings.Base64Url.Decode(..)”. We were having some problems with some of our values that had ‘+’ or ‘/’ characters in them. We followed Brock Allen’s advice at https://brockallen.com/2014/10/17/base64url-encoding/ where he said to use his custom decoder that would handle these characters correctly. Which is basically the same as changing the code above to “TextEncodings.Base64.Decode(..)” (NOTE: without the “Url” after the “Base64”).

    Reply
  13. Torsten Tiedt says

    November 10, 2016 at 9:46 pm

    Both absolutely incredible and impossible.

    Incredible that it works and impossible to do it yourself from scratch.

    After following your first tutorial series, I now jump from series to series picking what I need, and it really works out very well.

    Thank you very much once again,

    Torsten

    Reply
    • Taiseer Joudeh says

      November 12, 2016 at 12:11 am

      Hi Torsten, thanks for your comment and I’m glad to know that all the posts are helping you building your solution.

      Reply
      • Torsten Tiedt says

        November 13, 2016 at 10:14 pm

        Still working on authentication – still enthousiastic about your tutorials

        🙂

        Reply
  14. TJ says

    November 16, 2016 at 11:06 pm

    Hey Taiseer, I looked at this tutorial a while back and got it to work the first time. However, when I decided to migrate the code and make some name changes to the project and solution, I am no longer able to do the post call for /oauth/token

    I keep getting a 404 error and can’t figure out why that is the case. Why would I not be able to do the post call anymore? It’s like that route does not exist anymore and I can’t figure out why.

    Reply
  15. Mark says

    December 21, 2016 at 7:57 pm

    Excellent articles. Do you know if you can change Policies(and the claims/roles that belong to them) AFTER the application has loaded? My Executive wants to be able to configure “Groups” by using a UI/web page. I think I can consider the “Groups” to be Policies, but Policies load at startup. I’m not sure they can be changed after the app has loaded. Do you know if this is true or not and if not, is there another way to do this? Thanks(ASP.NET Core)

    Reply
    • Taiseer Joudeh says

      December 23, 2016 at 2:16 am

      Hello Mark,
      The bearer tokens are self-contained tokens, you can’t update them at run time. I recommend you to check “Reference Tokens” where you can achieve this, but the drawback that you will hit some store to get updated policies from.

      Reply
  16. Jeff says

    December 22, 2016 at 9:04 pm

    I am generating JWT just fine. The problem is when I test it on jwt.io it fails because something is apparently setting the alg property to “http://www.w3.org/2001/04/xmldsig-more#hmac-sha384”. jwt.io is expecting HMACSHA256.

    Reply
    • Taiseer Joudeh says

      December 23, 2016 at 2:23 am

      Hi Jeff, that is strange, are you using the same code base shared or you have changed the signing approach?

      Reply
      • Jeff says

        December 23, 2016 at 7:57 pm

        I figured it out. My original secret was created by Auth0. The secret was more than 32 bytes, that caused the ThinkTecture HmacSigningCredentials method to create the token using HMACSHA384. HmacSigningCredentials has a switch statement that sets the alg property based on the length of the secret.
        After creating a 32 byte secret which equated to HMACSHA256, which is compatible with jwt.io everything worked fine.

        Reply
  17. Aman says

    January 8, 2017 at 1:25 am

    Hi Taiseer
    I followed your tutorial with my sample application. I am getting the token but when I try to access one of the protected API’s I get “Authorization has been denied for this request.” error.
    I am using the same issuer without any trailing slashes. Can you please help me??

    Reply
    • Aman says

      January 8, 2017 at 9:12 am

      Seems like using AudienceId as empty string does not work. To resolve this issue I had to put AudienceId as “Any”.
      Thanks for this great tutorial.

      Reply
    • Taiseer Joudeh says

      January 8, 2017 at 9:46 pm

      Hello Aman,
      Can you try to debug the token using http://jwt.io and check the issuer matching what you have used, as well check the signature in jwt.io.

      Reply
      • Aman says

        January 9, 2017 at 6:03 pm

        Yes I can find the same issuer and signature is also verified. I guess issue was AudienceId was not assigned.

        Reply
  18. ahmad says

    January 13, 2017 at 8:24 pm

    powerful Article . Thank you….!!!

    Reply
  19. Sandeep says

    January 18, 2017 at 10:46 pm

    Hi Taiseer,

    This is a great tutorial, it is really helpful. The thing is, I’m facing a problem in startup file in configuration method. It says that
    “The inline constraint resolver of type ‘DefaultInlineConstraintResolver’ was unable to resolve the following inline constraint: ‘uid”.

    Everything was working fine before I applied Authorize

    I look forward to hear from you.

    Thank You!

    Best Regards,

    Sandeep Apsingekar

    Reply
  20. Sandeep says

    January 18, 2017 at 11:20 pm

    Hi,

    My bad I did a very simple typo error in the attribute routing. I fixed it now.

    Thank you!

    Best Regards,
    Sandeep

    Reply
    • Taiseer Joudeh says

      January 22, 2017 at 10:41 pm

      No problem, happy you found a solution 🙂

      Reply
      • Sandeep Apsingekar says

        March 22, 2017 at 1:01 am

        Thank You! Great tutorial I have learnt alot from this. Look forward to follow new tutorials from you.

        Reply
        • Taiseer Joudeh says

          March 26, 2017 at 1:20 am

          You are welcome, happy to hear this 🙂

          Reply
  21. Alex says

    January 28, 2017 at 7:47 am

    Hi Taiseer,
    now that I have this working, by using the same token mechanism, what would it take to expose the rest of the api (no credentials included) to the outside?

    Reply
    • Alex says

      January 28, 2017 at 7:51 am

      never mind, starting part 4 made me realize the answer is there.
      Thank you
      Alex

      Reply
  22. Yorkie says

    February 3, 2017 at 1:37 am

    Hi,

    Can you assist me in getting the expiry and not before times validated. I have attempted to add TokenValidationParameters to:

    app.UseJwtBearerAuthentication(
    new JwtBearerAuthenticationOptions
    {
    AuthenticationMode = AuthenticationMode.Active,
    AllowedAudiences = new[] { audience },
    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
    {
    new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
    },
    TokenValidationParameters = validationParameters
    });

    Where

    TokenValidationParameters validationParameters = new TokenValidationParameters
    {
    ValidateLifetime = true
    };

    However this results in all requests being rejected. Why?

    Thanks for the articles, they have been very informative.

    Reply
    • Taiseer Joudeh says

      February 14, 2017 at 1:26 am

      You are welcome, but could you elaborate more? I didn;t get what you are trying to achieve.

      Reply
      • Mahmoud Dorghamy says

        June 15, 2021 at 9:15 pm

        // Api controllers with an [Authorize] attribute will be validated with JWT
        app.UseJwtBearerAuthentication(
        new JwtBearerAuthenticationOptions
        {
        AuthenticationMode = AuthenticationMode.Active,
        AllowedAudiences = new[] { audienceId },
        IssuerSecurityKeyProviders = new IIssuerSecurityKeyProvider[] {
        new SymmetricKeyIssuerSecurityKeyProvider(issuer, audienceSecret)
        }
        });

        Reply
  23. York says

    February 3, 2017 at 2:57 pm

    Hi, I cant seem to work out how to get the Authorize attribute to validate the Token expiry and not before date time. I must be missing something simple.

    Reply
  24. Tuan Nguyen says

    February 5, 2017 at 12:16 pm

    I have a error “XMLHttpRequest cannot load http://localhost:51860/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 ‘http://localhost:3000’ is therefore not allowed access. The response had HTTP status code 400.” when I try send request from domain localhost:3000 to URL localhost:51860/oauth/token?

    Reply
    • Taiseer Joudeh says

      February 14, 2017 at 1:22 am

      This is CORS issue, make sure that the server you send request to contains the client “JS” URL in the “Access-Control-Allow-Origin” of the server.

      Reply
      • Diego says

        September 15, 2017 at 11:01 pm

        Hi Taiseer,

        Thank you for your Job.

        Can I add a determinate list of URL into “Access-Control-Allow-Origin” instead of “*” ?

        Reply
      • David says

        October 31, 2020 at 10:21 am

        Thanks for putting this together. It has saved me weeks of work! But, I am also having the same problem. Every endpoint within the owin controllers and my own work fine. The only one that doesn’t is the magical /oauth/token endpoint. I’ll be honest and say I do not understand how this special endpoint works, but it does very nicely within the same domain. Cross domain, I get CORS errors.

        Reply
  25. Rahul says

    February 25, 2017 at 6:24 pm

    Thank you very much Taiseer Joudeh.
    This is a great tutorial !!!

    Reply
    • Taiseer Joudeh says

      March 5, 2017 at 3:03 am

      You are welcome Rahul, happy to hear it was useful 🙂

      Reply
  26. Kulasekaralwar says

    March 4, 2017 at 8:10 am

    Hi

    I am getting following error. Please help

    {“error”:”unsupported_grant_type”}

    Reply
  27. Kulasekaralwar says

    March 4, 2017 at 9:00 am

    Hi,

    Awesome work, Great tutorial.

    Reply
    • Taiseer Joudeh says

      March 5, 2017 at 2:34 am

      Thanks for your message, but what is the grant type you are using?

      Reply
  28. Kulasekaralwar says

    March 9, 2017 at 7:29 am

    It was pointing to differenting database. Thank you very much very nice tutorial, I happy with your tutorial. why don’t you publish part – 6 please

    Reply
    • Diego says

      September 15, 2017 at 10:54 pm

      I think the same, maybe the next part could be in Angular 4.

      Reply
  29. marzouk says

    April 1, 2017 at 3:46 pm

    I have 2 web apps one worked as authorization server and also have some resources and another one contains some resources. I tried here to follow thw JWT Authentication but it didn’t work:
    http://stackoverflow.com/questions/43156228/authorization-has-been-denied-for-this-request-using-jwt-everytime
    I may forgot some steps or misunderstand others but i tried to follow the tutorial steps

    Reply
    • Taiseer Joudeh says

      April 8, 2017 at 6:25 pm

      Hi Marzouk, dropped you a comment on SO.

      Reply
      • Daniel says

        February 20, 2019 at 4:25 pm

        Getting the same error any help?
        {
        “message”: “Authorization has been denied for this request.”
        }

        Reply
      • Daniel says

        February 20, 2019 at 4:41 pm

        The issuer for the TokenConsumer method is different from my localhost would that cause any problems? I am getting errors similar to https://stackoverflow.com/questions/43156228/authorization-has-been-denied-for-this-request-using-jwt-everytime

        Reply
  30. Stephan says

    June 9, 2017 at 6:42 pm

    Please how to generate the Audience Id and Audience Secret ???

    Reply
    • Taiseer Joudeh says

      June 13, 2017 at 12:46 am

      Hi Stephan,
      Generating those values are up to you, you can use GUID for Audience ID and use whatever secret you want

      Reply
      • Achraf says

        February 21, 2018 at 3:42 pm

        Taiseer Joudeh i didnt really understand hwo to generate the Audience ID and Audience Secret with this project , can you provide us how to do so ?

        thank you !

        Reply
        • Adam says

          July 19, 2018 at 7:33 pm

          For Audience ID you can use :

          var audienceId = Guid.NewGuid().ToString(“N”);

          Reply
    • Oscar says

      August 10, 2020 at 5:21 am

      HI,
      you could also use a password generator website:
      https://passwordsgenerator.net/

      Reply
      • Vivian Chen says

        December 1, 2022 at 9:03 pm

        The site doesn’t load, maybe try this one.
        https://passwords-generator.org

        Reply
  31. Shannon says

    June 16, 2017 at 4:56 am

    Hi Taiseer,

    Great articles but it seems that this approach will not work with the latest Visual Studio 2017 Community version and latest version of WebApi. Always get “Authorization has been denied for this request.” when using the [Authorize] attribute. Any ideas? Thanks

    Reply
  32. Martin Wang says

    June 22, 2017 at 12:58 pm

    I got an issue about “Could not load type ‘System.IdentityModel.Tokens.TokenValidationParameters'”
    and I found System.IdentityModel.Tokens.Jwt 5.0 is not compatible with Katana 3,
    So need to downgrading to v4
    see this post…https://github.com/IdentityServer/IdentityServer3/issues/3017

    Reply
  33. Brett says

    June 29, 2017 at 7:50 pm

    Great write up. Thanks for taking the time to do it.

    Reply
  34. Varsha says

    August 2, 2017 at 3:48 pm

    I am following your post and found it really useful. Currently I got stuck to generate “as:AudienceId” and “as:AudienceSecret” keys. Can you please provide block of code of this implementation. Its difficult to understand the ‘implementation’ https://github.com/tjoudeh/JWTAspNetWebApi/blob/master/AuthorizationServer.Api/AudiencesStore.cs .

    Reply
    • Varsha says

      August 4, 2017 at 9:07 am

      I have generated the values using below code (snippet from https://github.com/tjoudeh/JWTAspNetWebApi/blob/master/AuthorizationServer.Api/):

      using Microsoft.Owin.Security.DataHandler.Encoder;
      using System;
      using System.Security.Cryptography;

      namespace ConsoleApplication3
      {
      class Program
      {
      static void Main(string[] args)
      {
      var clientId = Guid.NewGuid().ToString(“N”);

      var key = new byte[32];
      RNGCryptoServiceProvider.Create().GetBytes(key);
      var base64Secret = TextEncodings.Base64Url.Encode(key);

      Console.WriteLine(“CliendID : ” + clientId);
      Console.WriteLine(“Base64 : ” + base64Secret);
      Console.ReadLine();
      }
      }
      }

      Thanks.

      Reply
  35. Varsha says

    August 4, 2017 at 8:58 am

    Nice explanation. I am having doubt related to my project architecture. I want to create 3 Layer architecture with presentation layer(AngularJs), business logic layer (Web API) and data access layer(DAL) which would use the same DB for the authentication as for the other data.
    Is there any way to separate my data access layer from business logic layer with OWIN (JWT) authentication ?

    Please help.

    Reply
  36. Daniel says

    August 10, 2017 at 9:30 pm

    HI Taiseer Joudeh,

    After following your tutorial the access token that was generated does not contain three parts so it shows invalid on jwt.io

    this is an example of the access token that was generated

    {“access_token”:”d0eHEjrCu7AoX1nKnyTM-IHYi2R2sD_YjozMzFKPYnFFMr2v8zTZX_fUaCIxkhB0Y6N-FoTxN9J67wQqRvQNrrkL2WxfyE_lC2h3OsflPosVRHQtRk42P7jqAMakpfYRk721fkW0PpKYYThQjkiqT3Y0pksg1z0K2qZpB0pQPh–upTmhWsUfAluxJiStsI7n_qtNveo1me8gl5tmkstAD0GuJrY6zDlJKWtATcNiSy-eJuXTAjUR2ApqP_FpYhXrssAim6QZUMsG_5uatbfVA”,”token_type”:”bearer”,”expires_in”:1799,”as:client_id”:””,”userName”:”SuperPowerUser”,”.issued”:”Thu, 10 Aug 2017 16:08:48 GMT”,”.expires”:”Thu, 10 Aug 2017 16:38:48 GMT”}

    Reply
  37. djama says

    August 18, 2017 at 5:18 pm

    Hi Taiseer,

    Thanks for your time and your knowledge you are sharing with us , may GOD blessed You for that.

    you said ” 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.”
    In case we want to validate the request if our client is not trusted, can you provide the code for it or a link that deals with it.

    Thanks
    Djama from Ivory coast

    Reply
  38. Tuan Nguyen says

    October 9, 2017 at 12:56 pm

    Hi Taiseer,

    I run demo not successfully, sql database script not found from your solution.

    Please give me a database script.

    Thanks
    Tuan Nguyen.

    Reply
    • Tuan Nguyen says

      October 10, 2017 at 6:02 am

      I have just found in issue config, we used Entity Data Migration.

      Thanks Taiseer.

      Reply
  39. Abdul Khadar says

    May 15, 2018 at 3:24 pm

    hi,
    its a great article for me to start with web api. can you clarify what is the use if audience in this project? Is the audience values changes for the each user try to login

    Reply
  40. Adam says

    August 29, 2018 at 11:34 pm

    Hi, fantastic article indeed! I followed it all the way and it’s worked perfectly well.

    I would however love to implement a Whitelist of tokens against the User, I have created a table to host a JTI Claim value as well as the ClientId (Audience) and also the User it is against, I have a Unique Constraint to allow only one set of ClientId/ApplicationId and User at any one time.

    I would now love to know where to add the additional logic so that the [Authorize] attribute also checks against this table to ensure that the JTI claim within the JWT is listed against the Specified User and for this Audience…

    I suspect it needs to be added to the JwtBearerAuthenticationOptions somewhere but I am unsure of where..?

    Please help!

    Thanks

    Reply
  41. darshil says

    November 29, 2018 at 3:09 pm

    Even if i am not putting [Authorize] on my Controller it will throw “Authorization has been denied for this request.” Can you help me in this.? I don’t want to authenticate whole controller. Just want to authenticate some actions only. How i can do that?

    Reply
  42. Jaime says

    December 1, 2018 at 3:07 am

    When user is incorrect, a Bad Request is received instead of the invalid grant.

    I have this code in GrantResourceOwnerCredentials of my custom OAuthAuthorizationServerProvider

    var userManager = context.OwinContext.GetUserManager();

    ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

    if (user == null)
    {
    context.SetError(“invalid_grant”, “El nombre de usuario o la contraseña no son correctos.”);
    return;
    }

    if (user.Locked)
    {
    context.SetError(“invalid_grant”, “El usuario está bloqueado. Contáctese con el administrador.”);
    return;
    }

    When user is invalid, user is null and the method

    context.SetError(“invalid_grant”, “El nombre de usuario o la contraseña no son correctos.”);

    is executed. After that, client receives a Bad Request response with this header:

    Cabeceras de la respuesta (346 B)
    Cache-Control
    private
    Content-Length
    4901
    Content-Type
    text/html; charset=utf-8
    Date
    Fri, 30 Nov 2018 23:49:44 GMT
    Expires
    -1
    Pragma
    no-cache
    Server
    Microsoft-IIS/10.0
    X-Powered-By
    ASP.NET
    X-SourceFiles
    =?UTF-8?B?QzpcV29ya2luZ0ZvbGRl…Edlc3RvckRvY1dlYlxUb2tlbg==?=

    any help on this, please?

    Thanks
    Jaime

    Reply
  43. Dammu Suresh says

    January 20, 2019 at 6:17 pm

    {
    “Message”: “Authorization has been denied for this request.”
    }

    {“access_token”:”HGDowgl4pJky_h—n-Bfl7OoTTmsP5vwS2-ZfZRvRTJRP_WZkI1SqRez111DISwBXY_FJqMZJSIw3Luvx08nBoU8-qkWRFKinRmZUsJ6II-4sXfYM7rbDnt3vqy51oI5FPKHsPx-lulb3rLFwQpm272czDVjy4oynpzaFVKQJ5HiZhJp0fUyc3394PzL4hvSSmb93dieCJ6xdm3pXWVkntA-KJXLiwDzf2wrmsKFHdhospygQA1q9n41Ycf1x4eJ4tCNgmtzA79nX0kf9cogIaTp-AG4VJtQRdS_7rGH9Kv3lHTMa3rd6Czdhhki40R”,”token_type”:”bearer”,”expires_in”:1799}

    Reply
  44. Dammu Suresh says

    January 20, 2019 at 6:23 pm

    http://localhost:18292/api/audience/ChangePassword

    [Authorize]
    [Route(“ChangePassword”)]
    [HttpPost]
    public IHttpActionResult ChangePassword()
    {
    return Ok();
    }

    {“access_token”:”HGDowgl4pJky_h—n-Bfl7OoTTmsP5vwS2-ZfZRvRTJRP_WZkI1SqRez111DISwBXY_FJqMZJSIw3Luvx08nBoU8-qkWRFKinRmZUsJ6II-4sXfYM7rbDnt3vqy51oI5FPKHsPx-lulb3rLFwQpm272czDVjy4oynpzaFVKQJ5HiZhJp0fUyc3394PzL4hvSSmb93dieCJ6xdm3pXWVkntA-KJXLiwDzf2wrmsKFHdhospygQA1q9n41Ycf1x4eJ4tCNgmtzA79nX0kf9cogIaTp-AG4VJtQRdS_7rGH9Kv3lHTMa3rd6Czdhhki40R”,”token_type”:”bearer”,”expires_in”:1799}

    Error
    {
    “Message”: “Authorization has been denied for this request.”
    }

    I am using chrome postman

    [{“key”:”Authorization”,”value”:”bearer U2f5tusgwRRRkW4fYk82oOLk1Y8d_H8wWg9m5tEmufWuOG5F1HPIa4ckB_Le3BLvorkEZYVjun__rBSutge9WuOm-D1x1IIGFTWSPMB9m3-55gmouQldKgxtHdVzc6b1ZtH0AlxMm8QdLgfyzNUIQ5p1qtwmd-fmqCcHauJmkUEG5IlEaxlqQ9EJGzQdJrxgKh7Hwd88eBJh0APZkv9Aka2eDjE9Wuel4mo4VYXDD95z0GUjlZvMJ3rmSuBiwjyti6g26GhOHeibFw4YRq6B_PNUXUXC6F-3JCzcBCQq0H5ahGIQwKwzeYH2-RtYZXk7″,”description”:””}]

    Reply
  45. Desmond Oshiwambo says

    June 26, 2019 at 5:42 am

    Superb! Thank you Thank you. Implemented ok, working perfectly !!

    Reply
  46. John says

    June 27, 2019 at 4:25 am

    I have been following this tutorial from the first part. At the start of this tutorial you mention:

    “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”

    Had initially ignored that part in order to stay on track because everything was working fine. Up until the final part of testing.

    It just wont authorise for me. I keep getting the “message”: “Authorization has been denied for this request.” So i then decided to go and implement the part you recommended and came back and still faced the same issue.

    I have looked in every corner for help to get past this hurdle and no success. To the point that I am now confused which part should come before or after the other because the code from the other part doesn’t tie in with this one at all. Leaving me as a beginner on this topic completely confused and no lead on how to get over this hurdle

    Reply
    • tunahan says

      August 24, 2021 at 7:42 am

      I have the same problem and ı can not find any response at all. There are some pages which respond it but they are not relevant with my problem. I think it is related to installed packages version’s.

      Reply
    • tunahan says

      August 24, 2021 at 2:43 pm

      I have the same problem and ı can not find any response at all. There are some pages which respond it but they are not relevant with my problem. I think it is related to installed packages version’s.

      Reply
  47. Jalal says

    July 10, 2019 at 6:32 pm

    Thank you so much for taking the time to share your knowledge! This article has helped me out a great deal in understanding OAuth and tokens. Actually I cant providing the values for audience, and the audience secret
    please help me

    Reply
  48. Djama says

    August 24, 2019 at 4:31 pm

    hi all,

    i had this error:

    {
        “message”: “Permission was denied for this request.”
    }

    any help

    Reply
    • Matstar says

      January 11, 2020 at 3:25 am

      Make sure “app.UseWebApi(config)” is last line in “Configuration(IAppBuilder app)” method

      Reply
  49. Tahsin says

    September 14, 2019 at 6:20 pm

    Hi,

    I am getting this error on the CustomJwtFormat class:

    Argument 6: cannot convert from ‘Thinktecture.IdentityModel.Tokens.HmacSigningCredentials’ to ‘Microsoft.IdentityModel.Tokens.SigningCredentials’

    at the line:

    var signingKey = new HmacSigningCredentials(keyByteArray);
    ….
    —>var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);

    Can you help pls.

    Reply
  50. KC Frank says

    December 1, 2019 at 10:04 pm

    Please how can I consume this api using mvc5 fronted with jquery ajax?

    Reply
  51. Aniyan C says

    September 29, 2021 at 5:24 am

    HI,
    How can use this doc for .net 5 web api development? I read about there is no alternative of OAuthAuthorizationServerMiddleware in ASP.NET Core, the ASP.NET team simply decided not to port it.
    Can I implement OAuth authorization along with JWT ?

    Reply
« Older Comments

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About Taiseer

Husband, Father, Consultant @ MSFT, Life Time Learner... Read More…

Buy me a coffeeBuy me a coffee

Recent Posts

  • Invoking Dapr Services in Azure Container Apps using gRPC – Part 2
  • gRPC Communication In Azure Container Apps – Part 1
  • Azure Container Apps Volume Mounts using Azure Files – Part 12
  • Deploy Meilisearch into Azure Container Apps
  • Monitor Microservices App using Azure Managed Grafana

Blog Archives

Recent Posts

  • Invoking Dapr Services in Azure Container Apps using gRPC – Part 2
  • gRPC Communication In Azure Container Apps – Part 1
  • Azure Container Apps Volume Mounts using Azure Files – Part 12
  • Deploy Meilisearch into Azure Container Apps
  • Monitor Microservices App using Azure Managed Grafana

Tags

AJAX AngularJS API API Versioning ASP.NET ASP.NET 6 Authentication Autherization Server Azure Azure Active Directory B2C Azure AD B2C Azure Container Apps Azure Files Azure Storage Code First Dapr Dependency Injection Entity Framework ETag Foursquare API grpc IaC jQuery JSON JSON Web Tokens JWT KEDA Microservice Microsoft MVP Ninject OAuth OAuth 1.0 OData Redis Resource Server REST RESTful Single Page Applications SPA Token Authentication Tutorial Web API Web API 2 Web API Security Web Service

Search

Copyright © 2026 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in

%d