Authentication

In order to authenticate routes and subsequently use any of Ocelot’s claims based features such as authorization or modifying the request with values from the token, users must register authentication services in their Program as usual but they provide a scheme (authentication provider key) with each registration e.g.

var AuthenticationProviderKey = "MyKey";
builder.Services
    .AddAuthentication()
    .AddJwtBearer(AuthenticationProviderKey, options =>
    {
        // authentication setup via options initialization
    });

In this example MyKey is the scheme that this provider has been registered with. We then map this to a route in the configuration using the following AuthenticationOptions properties:

Single Authentication Scheme [1]

Property: AuthenticationOptions.AuthenticationProviderKey

We map authentication provider to a Route in the configuration e.g.

"AuthenticationOptions": {
  "AuthenticationProviderKey": "MyKey",
  "AllowedScopes": []
}

When Ocelot runs it will look at this routes AuthenticationProviderKey and check that there is an authentication provider registered with the given key. If there isn’t then Ocelot will not start up. If there is then the route will use that provider when it executes.

If a route is authenticated, Ocelot will invoke whatever scheme is associated with it while executing the authentication middleware. If the request fails authentication, Ocelot returns a HTTP status code 401 Unauthorized.

Multiple Authentication Schemes [2]

Property: AuthenticationOptions.AuthenticationProviderKeys

In the real world of ASP.NET Core, apps may need to support multiple types of authentication by a single Ocelot app instance. To register multiple authentication schemes (authentication provider keys) for each appropriate authentication provider, use and develop this abstract configuration of two or more schemes:

var DefaultScheme = JwtBearerDefaults.AuthenticationScheme; // Bearer
builder.Services
    .AddAuthentication()
    .AddJwtBearer(DefaultScheme, options => { /* JWT setup */ })
    // AddJwtBearer, AddCookie, AddIdentityServerAuthentication etc.
    .AddMyProvider("MyKey", options => { /* Custom auth setup */ });

In this example, the MyKey and Bearer schemes represent the keys with which these providers were registered. We then map these schemes to a route in the configuration as shown below.

"AuthenticationOptions": {
  "AuthenticationProviderKeys": [ "Bearer", "MyKey" ] // The order matters!
  "AllowedScopes": []
}

Afterward, Ocelot applies all steps that are specified for AuthenticationProviderKey as Single Authentication Scheme 1.

Note that the order of the keys in an array definition does matter! We use a “First One Wins” authentication strategy.

Finally, we would say that registering providers, initializing options, and forwarding authentication artifacts can be a “real” coding challenge. If you’re stuck or don’t know what to do, just find inspiration in our acceptance tests (currently for IdentityServer4 only) [3].

JWT Tokens

If you want to authenticate using JWT tokens maybe from a provider like Auth0, you can register your authentication middleware as normal e.g.

var AuthenticationProviderKey = "MyKey";
builder.Services
    .AddAuthentication()
    .AddJwtBearer(AuthenticationProviderKey, options =>
    {
        options.Authority = "test";
        options.Audience = "test";
    });
builder.Services
    .AddOcelot(builder.Configuration);

Then map the authentication provider key to a route in your configuration e.g.

"AuthenticationOptions": {
  "AuthenticationProviderKeys": [ "MyKey" ],
  "AllowedScopes": []
}

JWT Tokens Docs

Identity Server Bearer Tokens

In order to use IdentityServer bearer tokens, register your IdentityServer services as usual in Program with a scheme (key). If you don’t understand how to do this, please consult the IdentityServer documentation.

var AuthenticationProviderKey = "MyKey";
Action<JwtBearerOptions> options = o =>
{
    o.Authority = "https://whereyouridentityserverlives.com";
    // ...
};
builder.Services
    .AddAuthentication()
    .AddJwtBearer(AuthenticationProviderKey, options);
builder.Services
    .AddOcelot(builder.Configuration);

Then map the authentication provider key to a route in your configuration e.g.

"AuthenticationOptions": {
  "AuthenticationProviderKeys": [ "MyKey" ],
  "AllowedScopes": []
}

Auth0 by Okta

Yet another identity provider by Okta, see Auth0 Developer Resources.

Add the following, at minimum, to your startup Program:

var OktaProviderKey = "MyKey";
builder.Services
    .AddAuthentication()
    .AddJwtBearer(OktaProviderKey, o =>
    {
        var conf = builder.Configuration;
        o.Audience = conf["Authentication:Okta:Audience"]; // Okta Authorization server Audience
        o.Authority = conf["Authentication:Okta:Server"]; // Okta Authorization Issuer URI URL e.g. https://{subdomain}.okta.com/oauth2/{authidentifier}
    });
builder.Services
    .AddOcelot(builder.Configuration);

var app = builder.Build();
await app
    .UseAuthentication()
    .UseOcelot();
await app.RunAsync();

In order to get Ocelot to view the scope claim from Okta properly, you have to add the following to map the default Okta scp claim to scope:

// Map Okta "scp" to "scope" claims instead of http://schemas.microsoft.com/identity/claims/scope to allow Ocelot to read/verify them
JsonWebTokenHandler.DefaultInboundClaimTypeMap.Remove("scp");
JsonWebTokenHandler.DefaultInboundClaimTypeMap.Add("scp", "scope");

Okta Notes

  1. Issue 446 contains some code and examples that might help with Okta integration.

  2. Here is documentation for better clarity on claims mapping: Mapping, customizing, and transforming claims in ASP.NET Core.

  3. It is highly advisable to read and understand the Warning related to the critical changes in authentication when utilizing .NET 8. [4]

Allowed Scopes

If you add scopes to AllowedScopes, Ocelot will get all the user claims (from the token) of the type scope and make sure that the user has at least one of the scopes in the list.

This is a way to restrict access to a route on a per scope basis.

Warning

.NET 8 introduced a breaking change [4] where JwtSecurityToken was replaced with JsonWebToken to enhance performance and reliability. Consequently, their handlers were changed JwtSecurityTokenHandler to JsonWebTokenHandler. For versions prior to .NET 8, use the previous classes.

Future

We invite you to add more examples if you have integrated with other identity providers and the integration solution is working. Please open a “Show and tell” discussion in the repository.