Security update: Make sure you read this security advisory if you handle JWTs in your code. The examples and sample code in this article have been updated to use the fixed version of the affected packages.

Token authentication is quickly becoming a de facto standard for modern single-page applications and mobile apps. Even traditional server-rendered applications and web APIs can take advantage of token authentication. The benefits are great: less server state to manage, better scalability, and a consistent identity and authentication mechanism across web and mobile clients.

If you need a refresher on how tokens work, read our overview of token authentication and JWTs. All clear? Great!

Token authentication in ASP.NET Core is a mixed bag. The ability to protect routes with Bearer header JWTs is included, but the ability to generate the tokens themselves has been removed and requires the use of custom middleware or external packages. Despite this, both MVC and Web API applications can benefit from using tokens for authentication, and it turns out it’s not very hard to set up.

How do you implement both sides of token authentication – token verification and token generation – on the new ASP.NET Core stack? I’ll break down the process step by step. All of the code in this post can be found on Github.

Cookies or Headers for Authentication?

First, some background. Authentication tokens (such as JWTs) are typically transmitted in the HTTP Authorization header, like this:

Tokens can also be transmitted via browser cookies. Which transport method you choose (headers or cookies) depends on your application and use case. For mobile applications, headers are the way to go.

For web applications, we recommend using HttpOnly cookies instead of HTML5 storage/headers, for better security against XSS attacks. It’s important to note that using cookies means that you need to protect your forms against CSRF attacks (by using ASP.NET Core’s AntiForgery features, for example).

Validating Tokens in ASP.NET Core

First, you’ll need to create a SecurityKey from your secret key. For this example, I’m creating a symmetrical key to sign and validate JWTs with HMAC-SHA256. You can do this in your Startup.cs file:

Validating JWTs in Headers

In your Startup class, you can use the UseJwtBearerAuthentication method in the Microsoft.AspNetCore.Authentication.JwtBearer package to require a valid JWT for your protected MVC or Web API routes:

With this middleware added to your application pipeline, any routes protected with [Authorize] will require a JWT that passes the following validation requirements:

  • The signature matches your server’s secret key
  • The expiration date (exp claim) has not passed
  • The not-before date (nbf claim) has passed
  • The Issuer (iss) claim matches “ExampleIssuer”
  • The Audience (aud) claim matches “ExampleAudience”
  • If there is not a valid JWT in the Authorization header, or it fails these validation steps, the request will be rejected. If you’re not familiar with the JWT spec, the Issuer and Audience claims are optional. They are being used here to identify the application (issuer) and the client (audience).

    Validating JWTs in Cookies

    Out of the box, the ASP.NET Core cookie authentication middleware doesn’t support validating JWTs passed via cookies. You’ll need to create a custom ISecureDataFormat implementation that validates a JWT string.

    Since you’re only validating tokens, not creating them, you only need to implement the Unprotect method. The heavy lifting can be handled by the JwtSecurityTokenHandler class in the System.IdentityModel.Tokens.Jwt namespace. The full custom formatter class looks like this:

    Wire this class up with UseCookieAuthentication in your Startup.cs file:

    That’s it!

    If an incoming cookie named access_token contains a valid JWT, your protected MVC or Web API routes will be authorized. If you want, you can do additional validation of the JWT claims (or copy the JWT claims into the ClaimsPrincipal object) inside of CustomJwtDataFormat.Unprotect.

    If you’re using cookies to transport your JWTs between the browser and the server, we recommend the following best practices for security:

  • Set the HttpOnly flag
  • Set the Secure flag as well, if your site is hosted on HTTPS (and it should be!)
  • Use the [ValidateAntiForgeryToken] attribute on any forms that accept a POST
  • That takes care of the validation side of token authentication, but what about generating the tokens themselves?

    Generating Tokens in ASP.NET Core

    Back in the ASP.NET 4.5 days, the UseOAuthAuthorizationServer middleware provided an endpoint that could easily generate tokens for your application. However, the ASP.NET Core team decided not to port it to ASP.NET Core.

    Never fear! I’ll demonstrate how to write a simple token-generating middleware from scratch, and then conclude with a few links to pre-built solutions that could save you some time.

    Writing a Simple Token Endpoint

    First, you’ll need a simple POCO (plain ol’ CLR object) to hold a few options for the middleware class you’ll write. Create a new class called TokenProviderOptions.cs:

    Now you can build the middleware class itself. The basic pattern for ASP.NET Core middleware is this:

    This scaffolding creates a middleware class that can be added to the ASP.NET Core application pipeline and accepts a TokenProviderOptions instance as a parameter. When a request enters the pipeline, the Invoke method checks the request path and skips if it doesn’t match the exact path the middleware should be handling (such as /token or /api/token). The token endpoint also shouldn’t respond to anything but a POST with a form-urlencoded body, so the request method and Content-Type are checked as well.

    The heavy lifting happens in GenerateToken. This method needs to validate a user identity (given a username and password), and generate a signed token (JWT) to pass back to the client if that identity exists:

    Most of this method is just plumbing code. It uses the JwtSecurityToken class to build up a JWT payload, and then JwtSecurityTokenHandler writes it to an encoded string. You can store any custom claim you want in the payload by simply adding it to the claims array.

    The task of validating a user’s identity given their username and password is further abstracted away to the GetIdentity method. In a real application, you’d plug this into your user database or an identity framework like ASP.NET Core Identity. For the purposes of this example, you can hardcode the lookup:

    All done! You can wire the new middleware class up in Startup.cs by adding the middleware to your application pipeline:

    Once you’ve added it, fire up the application and use a tool like Fiddler or Postman to send a POST request to the new endpoint:

    If the username and password are valid, you’ll get a token response:

    You can use a tool like to decode the JWT and see the payload.

    That’s it! You now have a endpoint that issues JWTs for valid users. If you’re writing a mobile or single-page application or web API, you can store the JWT and send it in the Authorization header on subsequent requests. If you want to store the JWT in a browser cookie, you’ll need to make a small modification to the endpoint so that it adds a cookie to the response.

    Other ASP.NET Core Authentication Solutions

    This example works, but it’s simple. It doesn’t support refresh tokens or other methods of exchanging user credentials for an access token. There are some community-led efforts to build rich ASP.NET Core token authentication functionality:

  • AspNet.Security.OpenIdConnect.Server – Similar to the OAuth Authorization Server middleware for ASP.NET 4.x.
  • OpenIddict – Wraps OpenIdConnect.Server up into an easier-to-use package that plugs into ASP.NET Identity.
  • IdentityServer4 – A port of Thinktecture IdentityServer3 to .NET Core (currently in beta).
  • These solutions are much more powerful, but are also more complex to install and configure. If you want a powerful and simple solution, check out the Stormpath ASP.NET Core integration. This package will add all of Stormpath’s token management features to an ASP.NET Core project with two lines of code. You can learn more about Stormpath’s approach to token management with these resources:

  • Overview of Token Authentication Features
  • How Token Authentication Works in Stormpath
  • Use JWTs the Right Way!
  • Thanks for reading! Feel free to dig into the full code on Github. If you have any questions about token authentication, leave me a comment below.

    By the way, I’ll be speaking on ASP.NET Core Token Authentication at KCDC in Kansas City in June 2016. If you’re in the area, come say hi!

    • jomargon

      Thanks! What is the best way to implement logout() or invalidate the token?

      • Nate Barbettini

        Deleting the token on the client side is essentially “logging out” in this approach.

    • Ibrahim

      What’s the difference between issuing the token via middleware vs via a custom controller?

      • Nate Barbettini

        No real practical difference. I packaged things up into a middleware component here to make it reusable.

    • MaheshB

      How do I use the access token generated for the next subsequent requests.

      • Nate Barbettini

        Either by attaching the token to the headers of subsequent requests (using JavaScript), or by storing the token in a cookie and letting the browser send it to the server for you.

    • Mateus Leonardi

      Thanks Nate for this article, it’s very useful.
      I followed your steps but my home page in my Angular2 is not loading.
      How can I set the routes allowed to access without token?
      I would like to have a couple of pages with free access.
      Thanks in advance.

      • Nate Barbettini

        In a SPA, you will typically secure some or all of the backend API. You can leave the AuthorizeAttribute off of the API routes that you want to be unprotected.

        • Mateus Leonardi

          I added the [AllowAnonymous] to my HomeController but it’s returning error code 400.
          This controller is responsible to call my SPA start page.
          Should I configure something different? Is there a pattern name?
          Thanks in advance.

        • Nate Barbettini

          Error 400 doesn’t sound right. Are there any error details? What happens if you put no attributes on HomeController?

        • Mateus Leonardi

          I found the issue. I can’t use the attribute anti forgery. It’s working now. Thanks you!

    • Mateus Leonardi

      Thanks Nate for this article, it’s very useful.
      I followed your steps but my home page in my Angular2 is not loading the home page.
      How can I set the routes allowed to access without token?
      Thanks in advance.

    • Arn Vanhoutte

      Hey Nate, great tutorial! I managed to implement this tokensystem in my application, but I have a little question. How can I check if a user is signed it (eg if the there is a valid token in the request) within the method? So with the [Authorize] ?

      So I have controller, and in that controller I want to check if the user is signed in. I thought of using this:

      if (_signInManager.IsSignedIn(ClaimsPrincipal.Current))

      but it does not work since ClaimsPrincipal.Current is always null

      • Nate Barbettini

        Is HttpContext.User also null?

        • Arn Vanhoutte

          Yeah it was, but I found the problem. My ApiController was not inheriting from Controller. Adding : Controller fixed it

        • Nate Barbettini

          Glad you got it working!

    • Suresh Sankar

      how to maintain token for multiple service call? if it’s possible to maintain single token to access multiple service call?


      • Nate Barbettini

        You need some way to store the token on the client. For a web app, that means cookies or Web Storage.

    • Mieszko Misztal

      Where in the code is line to call Unprotect method each request or it doesn’t work like that?

      • Nate Barbettini

        That method is called by the framework. You don’t have to call it yourself. Try putting a throw statement inside, you’ll see the stack trace in the logs. 🙂

        • Mieszko Misztal

          Thanks alot for answer, I musth ave done something wrong because the method is not being invoked;(

    • Sam Jost

      The cookie authentication in ASP.NET Core uses some Kind of signed token in the cookie, which can be protected by setting httponly and secure – is there a benefit of using jwts instead of the integrated cookie auth other than interoperability with bigger single-sign-on-systems?

      • Nate Barbettini

        It’s similar but not exactly the same. The default cookie auth in ASP.NET Core is a traditional session approach, while JWTs are typically used in a stateless/token approach. Either one can work and there are pros and cons of each. With stateless tokens, you have to worry less about server state, but things like revocation become trickier.

        • Sam Jost

          Actually the ASP.NET Core UseIdentity seems to work stateless: Even when I delete a user from the database or even drop and recreate the full database, as long as the cookie persists the user will be logged on by the identity Framework.
          So ist like jwts: I don’t have to worry about server state and revocation is tricky.
          Why do you think it’s a session cookie?

        • Nate Barbettini

          Ah, interesting. I hadn’t tried that. My knowledge might be stuck back in pre-Core land. I need to do some further research on how it’s handled in Core.

    • Christopher J.

      Thank you Nate. This had been very helpful.
      I upgraded the stability of my app, and learned new things!
      Please keep going :).
      Is there a stream for your conference anywhere ?

    • Nora Youssef

      Thanks Nate for your great article,

      I have managed creating access token through the endpoint /api/token, but when I tried to access an action with [Authorize] it didn’t authenticate my user!
      Actually I don’t know how the Authorize attribute interprets my request searching for the access token.

      the client side simple ajax as:
      function getValues()
      url: “…/api/values”,
      headers: { ‘Authorization’: ‘Basic ‘ + accessToken, ‘Expires’: tokenExpires },
      method: “GET”,
      context: document.body,
      success: function (data) {
      Could you help in such a problem?

      • Nate Barbettini

        Do you have the UseJwtBearerAuthentication middleware in your pipeline? Also, the header should be Authorization: Bearer, not Basic. Basic is used for username/password login.

        • Nora Youssef

          It worked! Thanks a lot,
          I’ve another question, how shall I invalidate the generated token? for example, after a successful log off, I want to mark this token as invalid

        • Nate Barbettini

          Deleting the token on the client side effectively logs the user off. But the token isn’t truly invalid until it expires. In order to revoke or blacklist the token, you’d need to ID each token (the jti claim), and keep track of a blacklist on the server side.

        • Nora Youssef

          Yea I got it, but I am trying to avoid storing and checking all the generated tokens (the black list), what if I stored the only current/valid token and on sign out lets delete this value. I would do a check in O (1) but if I kept the black list it would be O(n). Do you agree with my suggestion or what do you see?

        • Nate Barbettini

          Having to store revoked tokens is one disadvantage of a token-based auth approach. You can keep the storage minimal, though, by only storing revoked tokens in the blacklist (no need to store everything, just any unexpired token that should not be used).

    • disqus_v9Gohxr4Q1

      SigningCredentials is not in Microsoft.IdentityModel.Tokens. Any advice?

    • Filip Reft Danielsson

      I don’t understand how you’re supposed to implement this with a normal login page. Should you first validate if the user and password is correct with your own api controller, (which can send back Succes/error message etc), and then make another call to /token with the same data to sign in the user? Thanks!