DEV Community

loading...
Cover image for Setting up an Authorization Server with OpenIddict - Part V - OpenID Connect

Setting up an Authorization Server with OpenIddict - Part V - OpenID Connect

Robin van der Knaap
Full stack developer: Jack of al trades, master of none.
Updated on ・3 min read

This article is part of a series called Setting up an Authorization Server with OpenIddict. The articles in this series will guide you through the process of setting up an OAuth2 + OpenID Connect authorization server on the the ASPNET Core platform using OpenIddict.

GitHub logo robinvanderknaap / authorization-server-openiddict

Authorization Server implemented with OpenIddict.


OpenIddict implements the OpenID Connect protocol, which is an identity layer on top of the OAuth2 protocol.
The implementation of the OpenID Connect protocol issues an extra token to the client application, called the identity token. This token contains user profile information which can be used by client applications to identify the end-user.

It's wise to keep your tokens small. Therefore, the OpenID Connect protocol offers the possibility to expose an userinfo endpoint from which clients can retrieve extra information about the end-user which is not stored in the identity token.

In this part we will see how to leverage the OpenID Connect protocol and how to add an endpoint for querying extra user information.

Enable OpenID Connect

As said, OpenIddict has implemented the OpenID Connect protocol. You can test this by requesting an extra scope called openid with Postman:

Alt Text

In the response you will find an identity token together with the access token.

To store extra profile information in the identity token, you can add claims in the Authorize method in the AuthorizationController when using the authorization code flow or add claims in the token endpoint if you are using the client credentials flow. Make sure to set the destination to IdentityToken. Here's an example using a default claim called email:

public async Task<IActionResult> Authorize()
{
    ...

    var claims = new List<Claim>
    {
        // 'subject' claim which is required
        new Claim(OpenIddictConstants.Claims.Subject, result.Principal.Identity.Name),
        new Claim("some claim", "some value").SetDestinations(OpenIddictConstants.Destinations.AccessToken),
        new Claim(OpenIddictConstants.Claims.Email, "some@email").SetDestinations(OpenIddictConstants.Destinations.IdentityToken)
    };

    ...
}
Enter fullscreen mode Exit fullscreen mode

It is also possible for a claim to have multiple destinations, so we can add a claim to the access token and the identity token if we want.

You can view the content of the identity token on jwt.io:

{
  "sub": "Robin van der Knaap",
  "email": "some@email",
  "oi_au_id": "e5e12b78-ddea-42df-8350-5b7bda36b07b",
  "azp": "postman",
  "at_hash": "iuzdujyas1p_1XjUuxtw9A",
  "oi_tkn_id": "7f0ae652-c997-4425-bda5-6d024ea3acb3",
  "aud": "postman",
  "exp": 1607684956,
  "iss": "https://localhost:5001/",
  "iat": 1607683756
}
Enter fullscreen mode Exit fullscreen mode

Userinfo endpoint

Besides the identity token, the OpenID Connect protocols also allows for an url to get information about the user. To leverage the userinfo endpoint, we need to enable the endpoint and set the url in Startup.cs first:

options
    .SetAuthorizationEndpointUris("/connect/authorize")
    .SetTokenEndpointUris("/connect/token")
    .SetUserinfoEndpointUris("/connect/userinfo");

options
    .UseAspNetCore()
    .EnableTokenEndpointPassthrough()
    .EnableAuthorizationEndpointPassthrough()
    .EnableUserinfoEndpointPassthrough();
Enter fullscreen mode Exit fullscreen mode

Now if you restart the authorization server and navigate to https://localhost:5001/.well-known/openid-configuration. You will see that the userinfo endpoint is added to public configuration file:

Alt Text

Next step is to implement the userinfo endpoint. We can decide for ourselves which user info we want to share with clients. We will add the method to the AuthorizationController:

[Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)]
[HttpGet("~/connect/userinfo")]
public async Task<IActionResult> Userinfo()
{
    var claimsPrincipal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;

    return Ok(new
    {
        Name = claimsPrincipal.GetClaim(OpenIddictConstants.Claims.Subject),
        Occupation = "Developer",
        Age = 43
    });
}
Enter fullscreen mode Exit fullscreen mode

The user info endpoint can only be accessed when the client has a valid access token. This is why we added the Authorize attribute. For this to work, we have to enable authorization in Startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseAuthentication();

    app.UseAuthorization();

    ...
}
Enter fullscreen mode Exit fullscreen mode

Now if we do a GET request to /connect/userinfo and use a valid access token, the response looks something like this:

Alt Text

Next

Next up, we will enable the usage of refresh tokens.

Discussion (4)

Collapse
rohans profile image
Rohan Singh

I could not get authorization to work without:

1) Enable validation (note: this snippet only works for authorizing requests within the same endpoint as the authorization server, such as the userinfo API)

services.AddOpenIddict()
    .AddServer(() =>
    {
        // ...
    })
    .AddValidation(options =>
    {
        // Import the configuration from the local OpenIddict server instance.
        options.UseLocalServer();

        // Register the ASP.NET Core host.
        options.UseAspNetCore();
    });
Enter fullscreen mode Exit fullscreen mode

2) Use the validation authentication scheme to authorize instead of the server's scheme

// Replace this:
//[Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)]
// With this:
[Authorize(AuthenticationSchemes = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)]
Enter fullscreen mode Exit fullscreen mode
Collapse
joepb profile image
Joep Beusenberg

Awesome catch. I think I'd never figured this out if you hadn't added this.
Also in the line below, you will need to use OpenIddictValidationAspNetCoreDefaults. Then it works flawlessly.

Collapse
keithn profile image
Keith Nicholas

Part VI - Integrating External Authorization Providers ... google/azure/facebook/twitter.... etc ? :)

Collapse
svenni profile image
svenniuwe

For me it is working without any change.