Implementing OpenID Implicit Flow using OpenIddict and Angular

This article shows how to implement the OpenID Connect Implicit Flow using OpenIddict hosted in an ASP.NET Core application, an ASP.NET Core web API and an Angular application as the client.


2017-05-27 Updated to ASP.NET Core 2.1, Angular 6.0.3

2017-11-24 Updated to ASP.NET Core 2, Angular 5, angular-auth-oidc-client

Three different projects are used to implement the application. The OpenIddict Implicit Flow Server is used to authenticate and authorise, the resource server is used to provide the API, and the Angular application implements the UI.

OpenIddict Server implementing the Implicit Flow

To use the OpenIddict NuGet packages to implement an OpenID Connect server, you need to use the myget server. You can add a NuGet.config file to your project to configure this, or add it to the package sources in Visual Studio 2017.

<?xml version="1.0" encoding="utf-8"?>
    <add key="NuGet" value="" />
    <add key="aspnet-contrib" value="" />

Then you can use the NuGet package manager to download the required packages. You need to select the key for the correct source in the drop down on the right hand side, and select the required pre-release packages.

Or you can just add them directly to the csproj file.

<Project Sdk="Microsoft.NET.Sdk.Web">


    <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0-rc1-final" />

    <PackageReference Include="AspNet.Security.OAuth.Validation" Version="2.0.0-rc2-final" />
    <PackageReference Include="Openiddict" Version="2.0.0-rc1-final" />
    <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0-rc1-final" />
    <PackageReference Include="OpenIddict.Mvc" Version="2.0.0-rc1-final" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.0-rc1-final" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0-rc1-final" />

    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />

    <Content Update="appsettings.json">

    <None Update="damienbodserver.pfx">


The OpenIddict packages are configured in the ConfigureServices and the Configure methods in the Startup class. The following code configures the OpenID Connect Implicit Flow with a SQLite database using Entity Framework Core. The required endpoints are enabled, and Json Web tokens are used.

public void ConfigureServices(IServiceCollection services)
	services.AddDbContext<ApplicationDbContext>(options =>
		// Configure the context to use Microsoft SQL Server.

		// Register the entity sets needed by OpenIddict.
		// Note: use the generic overload if you need
		// to replace the default OpenIddict entities.

	// Register the Identity services.
	services.AddIdentity<ApplicationUser, IdentityRole>()

	services.Configure<IdentityOptions>(options =>
		options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
		options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
		options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;

	// Register the OpenIddict services.
	services.AddOpenIddict(options =>
		// Register the Entity Framework stores.

		// Register the ASP.NET Core MVC binder used by OpenIddict.
		// Note: if you don't call this method, you won't be able to
		// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.

		// Enable the authorization, logout, userinfo, and introspection endpoints.

		// Note: the sample only uses the implicit code flow but you can enable
		// the other flows if you need to support implicit, password or client credentials.

		// During development, you can disable the HTTPS requirement.

		// Register a new ephemeral key, that is discarded when the application
		// shuts down. Tokens signed using this key are automatically invalidated.
		// This method should only be used during development.





		.AddJwtBearer(options =>
			options.Authority = "https://localhost:44319/";
			options.Audience = "dataEventRecords";
			options.RequireHttpsMetadata = true;
			options.TokenValidationParameters = new TokenValidationParameters
				NameClaimType = OpenIdConnectConstants.Claims.Name,
				RoleClaimType = OpenIdConnectConstants.Claims.Role

	var policy = new Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy();

	policy.SupportsCredentials = true;

	services.AddCors(x => x.AddPolicy("corsGlobalPolicy", policy));


	services.AddTransient<IEmailSender, AuthMessageSender>();
	services.AddTransient<ISmsSender, AuthMessageSender>();

The Configure method defines JwtBearerAuthentication so the userinfo API can be used, or any other authorisered API. The OpenIddict middlware is also added. The commented out method InitializeAsync is used to add OpenIddict data to the existing database. The database was created using Entity Framework Core migrations from the command line.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

            if (env.IsDevelopment())




            InitializeAsync(app.ApplicationServices, CancellationToken.None).GetAwaiter().GetResult();

Entity Framework Core database migrations:

> dotnet ef migrations add test
> dotnet ef database update test

The UserinfoController controller is used to return user data to the client. The API requires a token which is validated using the JWT Bearer token validation, configured in the Startup class.
The required claims need to be added here, as the application requires. This example adds some extra role claims which are used in the Angular SPA.

using System.Threading.Tasks;
using AspNet.Security.OAuth.Validation;
using AspNet.Security.OpenIdConnect.Primitives;
using OpeniddictServer.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

namespace OpeniddictServer.Controllers
    public class UserinfoController : Controller
        private readonly UserManager<ApplicationUser> _userManager;

        public UserinfoController(UserManager<ApplicationUser> userManager)
            _userManager = userManager;

        // GET: /api/userinfo
        [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        [HttpGet("userinfo"), Produces("application/json")]
        public async Task<IActionResult> Userinfo()
            var user = await _userManager.GetUserAsync(User);
            if (user == null)
                return BadRequest(new OpenIdConnectResponse
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The user profile is no longer available."

            var claims = new JObject();
            claims[OpenIdConnectConstants.Claims.Subject] = await _userManager.GetUserIdAsync(user);

            if (User.HasClaim(OpenIdConnectConstants.Claims.Scope, OpenIdConnectConstants.Scopes.Email))
                claims[OpenIdConnectConstants.Claims.Email] = await _userManager.GetEmailAsync(user);
                claims[OpenIdConnectConstants.Claims.EmailVerified] = await _userManager.IsEmailConfirmedAsync(user);

            if (User.HasClaim(OpenIdConnectConstants.Claims.Scope, OpenIdConnectConstants.Scopes.Phone))
                claims[OpenIdConnectConstants.Claims.PhoneNumber] = await _userManager.GetPhoneNumberAsync(user);
                claims[OpenIdConnectConstants.Claims.PhoneNumberVerified] = await _userManager.IsPhoneNumberConfirmedAsync(user);

            List<string> roles = new List<string> { "dataEventRecords", "dataEventRecords.admin", "admin", "dataEventRecords.user" };
            claims["role"] = JArray.FromObject(roles);

            return Json(claims);

The AuthorizationController controller implements the CreateTicketAsync method where the claims can be added to the tokens as required. The Implict Flow in this example requires both the id_token and the access_token and extra claims are added to the access_token. These are the claims used by the resource server to set the policies.

private async Task<AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user)
	var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

	var principal = await _signInManager.CreateUserPrincipalAsync(user);
	foreach (var claim in principal.Claims)
		if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)

		var destinations = new List<string>

		if ((claim.Type == OpenIdConnectConstants.Claims.Name) ||
			(claim.Type == OpenIdConnectConstants.Claims.Email) ||
			(claim.Type == OpenIdConnectConstants.Claims.Role)  )



	// Add custom claims
	var claimdataEventRecordsAdmin = new Claim("role", "dataEventRecords.admin");

	var claimAdmin = new Claim("role", "admin");

	var claimUser = new Claim("role", "dataEventRecords.user");


	// Create a new authentication ticket holding the user identity.
	var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity),
	new AuthenticationProperties(),

	// Set the list of scopes granted to the client application.


	return ticket;

If you require more examples, or different flows, refer to the excellent openiddict-samples .

Angular Implicit Flow client

The Angular application uses the AuthConfiguration class to set the options required for the OpenID Connect Implicit Flow. The ‘id_token token’ is defined as the response type so that an access_token is returned as well as the id_token. The jwks_url is required so that the client can ge the signiture from the server to validate the token. The userinfo_url and the logoutEndSession_url are used to define the user data url and the logout url. These could be removed and the data from the jwks_url could be ued to get these parameters. The configuration here has to match the configuration on the server.

The OidcSecurityService is used to send the login request to the server and also handle the callback which validates the tokens. This class also persists the token data to the local storage.

The OidcSecurityValidation class defines the functions used to validate the tokens defined in the OpenID Connect specification for the Implicit Flow.

The jsrsasign is used to validate the token signature and is added to the html file as a link.

Once logged into the application, the access_token is added to the header of each request and sent to the resource server or the required APIs on the OpenIddict server.

 private setHeaders() {

        console.log('setHeaders started');

        this.headers = new Headers();
        this.headers.append('Content-Type', 'application/json');
        this.headers.append('Accept', 'application/json');
        this.headers.append('Cache-Control', 'no-cache');

        let token = this._securityService.GetToken();
        if (token !== '') {
            let tokenValue = 'Bearer ' + token;
            console.log('tokenValue:' + tokenValue);
            this.headers.append('Authorization', tokenValue);

ASP.NET Core Resource Server API

The resource server provides an API protected by security policies, dataEventRecordsUser and dataEventRecordsAdmin.

using AspNet5SQLite.Model;
using AspNet5SQLite.Repositories;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace AspNet5SQLite.Controllers
    public class DataEventRecordsController : Controller
        private readonly IDataEventRecordRepository _dataEventRecordRepository;

        public DataEventRecordsController(IDataEventRecordRepository dataEventRecordRepository)
            _dataEventRecordRepository = dataEventRecordRepository;

        public IActionResult Get()
            return Ok(_dataEventRecordRepository.GetAll());

        public IActionResult Get(long id)
            return Ok(_dataEventRecordRepository.Get(id));

        public void Post([FromBody]DataEventRecord value)

        public void Put(long id, [FromBody]DataEventRecord value)
            _dataEventRecordRepository.Put(id, value);

        public void Delete(long id)

The policies are implemented in the Startup class and are implemented using the role claims dataEventRecords.user, dataEventRecords.admin and the scope dataEventRecords.

var guestPolicy = new AuthorizationPolicyBuilder()
	.RequireClaim("scope", "dataEventRecords")

services.AddAuthorization(options =>
	options.AddPolicy("dataEventRecordsAdmin", policyAdmin =>
		policyAdmin.RequireClaim("role", "dataEventRecords.admin");
	options.AddPolicy("dataEventRecordsUser", policyUser =>
		policyUser.RequireClaim("role",  "dataEventRecords.user");


Jwt Bearer Authentication is used to validate the API HTTP requests.

app.UseJwtBearerAuthentication(new JwtBearerOptions
	Authority = "https://localhost:44319/",
	Audience = "dataEventRecords",
	RequireHttpsMetadata = true,
	TokenValidationParameters = new TokenValidationParameters
		NameClaimType = OpenIdConnectConstants.Claims.Subject,
		RoleClaimType = OpenIdConnectConstants.Claims.Role

Running the application

When the application is started, all 3 applications are run, using the Visual Studio 2017 multiple project start option.

After the user clicks the login button, the user is redirected to the OpenIddict server to login.

After a successful login, the user is redirected back to the Angular application.



  1. Hi,

    I have implemented your code, but while testing am getting the following error in my angular app.

    Unexpected token ( in JSON at position 1.

    This error comes when AuthorizeCallback tries to decode the base64 for the token.


    1. Hi I have done a large update, you need to build the client app as well.

      npm install
      npm run build-production

      Greetings Damien

      1. I’m getting the same error when trying to use the latest version. It looks like it’s trying to parse the id_token as json, but the decoded version is not json.

  2. Extremely helpful, thank you!

    I’m adapting to use a SQL db, (I use db first so I’m working with the sql tables). I’ve gotten the client_id and redirect uri’s correct, but am at the stage when I click “login” I’m getting:

    error_description:Confidential clients are not allowed to retrieve an access token from the authorization endpoint.

    Can you point me in the right direction?


  3. Got it, it was the “Type” field of table OpenIddictApplications (was set to confidential, changed to public).

  4. All I get is “This is server routing, not angular routing”

    1. Hi Alfetta159, In the startup class you need to add the angular route so it won’t be handled by the server routing.

      Greetings Damien

      1. What is the point of not having it added?

        And how do I add it?

    2. You might want to use server routing for files, or MVC or whatever

      1. I’ve just updated code to OpenIddict 2.0.0-rc2-0792 and have successfully integrated custom OpenIddict table names using db first dotnet ef scaffolding. Server app coming up fine, angular app returning as above (“This is server routing…”). I’m sure this reflects my lack of familiarity of working with an angular app in a Visual Studio 2017 solution/project. Anything you can add to clarify the solution would be greatly appreciated

      2. In the startup class you need to add all the client routes, so that the MVC server app does n0t try to route it.

  5. […] There are some good examples of how to do this on the web, such as this article by Kévin Chalet or this one by Damien Bowden. Additionally, there are the ASP.NET Core/JavaScript samples for OpenIddict […]

  6. Great article.
    Can this code be updated to Core 2.0 and Angular 5 with latest openiddict please?

    1. yes, as soon as possible

    2. Many Thanks
      Will wait for it.

  7. Any plans soon to migrate to Core 2 and Angular 5?

  8. Updated ASP.NET Core 2, Angular 5, angular-auth-oidc-client

  9. Thanks a lot. This is exactly what was required. I have been a keen follower of your blogs.

  10. I tested the latest code.
    The authentication part is working OK.
    But while accessing resource server, it is throwing 404 error.
    Any help?

  11. The latest update works perfectly.
    Thanks a lot.
    A great article.

  12. I pulled your latest rep from github, and when I startup the project in vs2017, I an error “This site can’t be reached
    The webpage at https://localhost:44319/ might be temporarily down or it may have moved permanently to a new web address.”

    1. hi Clint, you might need to do a npm install, then a npm run build-dev, greetings Damien

  13. Peter Griffin · · Reply

    I have all the components running – auth server, resource server and the client. I was able to register a user via the UI, I can see the user in the DB. However when I try to log in (with correct credentials, I’m sure of it), I get a 400 Bad Request response from the auth server with the following message:

    error_description:The specified ‘redirect_uri’ parameter is not valid for this client application.

    VS has assigned a different port number to my resource server, but I’ve updated this everywhere in the code.

    1. Peter Griffin · · Reply

      I somehow got around the invalid_request by downloading the solution again, setting the resource server port to 44308 in the project properties, as this is what’s in the source files. I ran those servers. I changed the client back so that redirect port would be 44308. Now when I log in the auth server redirects me to https://localhost:44308 where I get a 404. No Angular app pops up, nothing happens. When I try to manually navigate to the urls of the controllers, I get a 401. Nothing about this solution works.

  14. Hi Peter, the github examples should work without changes, only the certs need to be excepted with the system running it. I run with IIS Express. I will check this again to make sure.

    Greetings Damien

    1. Peter Griffin · · Reply

      Hi Damien, sorry for the harsh words, I’m getting a bit frustrated here. Currently what happens when I log in is I get redirected to this url

      and there I get a 404. I know the resource server is running, because this url https://localhost:44308/index.html returns the index page.

      1. So the login to the STS is finished. The return URL is not been handled by the client application, maybe server routing first. You need that the client routing handles the return URL. Disable the server routing for this return URL. Note it works when you open the index static page because this is not handled by the server routing.

        Greetings Damien

  15. Peter Griffin · · Reply

    Thanks, I’ll try that. Did you get a chance to check your sample?

    1. I have updated the example, and tested it. seems to work

      1. Peter Griffin · ·

        Thanks. I’ve been sitting here for the past 3 hours just trying to get the projects to run. First I had to update my VS, as apparently it was old. Then I had to update then .NET SDK, then the .NET Core SDK. Then the ASPNET core app failed while starting, the ASPNET core web server output said it was unable to locate the correct aspnet core app version. It asked for 2.1.0-rc1, so I installed that one specifically. Now I get a compile time error:

        Error The project was restored using Microsoft.NETCore.App version 2.1.0-preview2-26406-04, but with current settings, version 2.1.0-rc1 would be used instead. To resolve this issue, make sure the same settings are used for restore and for subsequent operations such as build or publish. Typically this issue can occur if the RuntimeIdentifier property is set during build or publish but not during restore.

        Could you possibly tell me what to install/uninstall or which setting to change? Cause I’m at the end of my wits and just about ready to take out a hammer and smash my machine to bits.

      2. Peter Griffin · ·

        Nope, after spending several hours trying to get this updated version to run, I got to the exact same situation I had last time: auth server running, resource server running, client running. I am able to register a user, log in, and then am redirected to the resource server where I get a 404.
        I think it’s time for me to declare defeat and stop spending my time on this sample. I was really happy when I first saw it, cause I thought I could get my little side project started, without having to go through the pain of having to code the authentication infrastructure myself. But it keeps not working no matter what I do and I’m at the end of my mental capacity to continue trying.
        So long and thanks for all the help.

      3. Hi Peter

        Sorry to hear that 😦 Hope you have success building the new solution.

        Greetings Damien

  16. […] Implementing OpenID Implicit Flow using OpenIddict and Angular by Damien Bowden. […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

%d bloggers like this: