JSON Web Tokens (JWT)
Although Shuttle.Access supports identity name and password authentication, the preferred mechanism is to use JSON Web Tokens.
In order to support JWTs the relevant Web APIs would need to be configured to validate a provided token.
The Shuttle.Access.WebApi
may also be configured to expose OAuth
providers to the front-end that a user may select to authenticate themselves.
Web API configuration
Web APIs would need to reference package Shuttle.Access.RestClient
which provides a client that can access a Shuttle.Access.WebApi
deployment. The Shuttle.Access.AspNetCore
package will be added as a transient reference.
The following will add Authorization
header authentication handlers for the Shuttle.Access
and Bearer
schemes:
services
.AddAccessAuthorization(builder =>
{
webApplicationBuilder.Configuration.GetSection($"{AccessAuthorizationOptions.SectionName}").Bind(builder.Options);
});
This will bind the following to the options:
{
"Shuttle": {
"Access": {
"Authorization": {
"Issuers": [
{
"Uri": "https://sts.windows.net/{tenant-id}/",
"JwksUri": "https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys",
"IdentityNameClaimTypes": [ "upn", "appid" ],
"Audiences": [],
"ClockSkew": "00:05:00",
"SigningKeyCacheDuration": "01:00:00"
}
]
}
}
}
}
Whenever the Web API receives an Authorization
header for the supported schemes, it retrieves the session from the Shuttle.Access.WebApi
sessions endpoint (POST /v1/session/search
). If it cannot find a session, then one is created. To retrieve a session the identity requires the access://sessions/view
permissions, and in order to register a new session it requires the access://sessions/register
permission.
The incoming token has to contain an identifier of sorts that will be used for the Identity Name
. The token will be inspected and the first of the IdentityNameClaimTypes
that is located will be used as the identity name.
In order for the Web API to interact with the Shuttle.Access.WebApi
the caller also has to be authenticated. This is where the following configuration comes in:
service
.AddAccessClient(builder =>
{
builder.Options.BaseAddress = "http://localhost:5599";
// JWT `Bearer` preferred.
builder.AddBearerAuthenticationProvider(providerBuilder =>
{
providerBuilder.Options.GetTokenAsync = async (httpRequestMessage, serviceProvider) =>
{
// Obtain the token and pass it back.
// For example, here is a simple Azure token retrieval using package `Azure.Identity`.
var credential = new DefaultAzureCredential();
string scope = "https://management.azure.com/.default";
AccessToken token = await credential.GetTokenAsync(new TokenRequestContext(new[] { scope }));
return token.Token.
};
});
// Simple identity name/password.
builder.AddPasswordAuthenticationProvider(providerBuilder =>
{
providerBuilder.Options.IdentityName = "{web-api identity name}";
providerBuilder.Options.Password = "{web-api identity password}";
});
});
OAuth configuration
The OAuth
providers are configured in the appsettings.json
of the Shuttle.Access.WebApi
deployment:
{
"Shuttle": {
"OAuth": {
"DefaultRedirectUri": "http://localhost:3000/oauth",
"Providers": [
{
"Name": "GitHub",
"Authorize": {
"clientId": "{client-id}",
"Url": "https://github.com/login/oauth/authorize"
},
"Token": {
"clientId": "{client-id}",
"clientSecret": "{client-secret}",
"Url": "https://github.com/login/oauth/access_token"
},
"Data": {
"Url": "https://api.github.com/user"
},
"scope": "user:email"
},
{
"Name": "Microsoft",
"Authorize": {
"clientId": "{client-id}",
"Url": "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize",
"CodeChallengeMethod": "S256"
},
"Token": {
"clientId": "{client-id}",
"Url": "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token",
"ContentTypeHeader": "application/x-www-form-urlencoded",
"OriginHeader": "http://localhost:3000"
},
"Data": {
"Url": "https://graph.microsoft.com/v1.0/me",
"AuthorizationHeaderScheme": "Bearer",
"EMailPropertyName": "mail"
},
"Scope": "User.Read"
}
]
}
}
}
This is a generic OAuth
mechanism implemented by the Shuttle.OAuth package.