Authenticating to an IdentityServer4 service with an ASP.NET Core application is actually quite easy once you see it. It does require a basic understanding of the OpenID framework though. I’m first going to explain some basics and then I’ll show the code at the end.
IdentityServer4 will expose a set of endpoints that a client can authenticate with and get a token. There are two types of tokens that you can use:
-
JWT: These tokens have all the user claims encoded into them with an expiry time. They are signed by the authorization service with a certificate which is used to validate that they are valid.
-
Reference: The token is only a unique identifier to the full JWT token. When a client supplies the reference token, the api will need to validate it against an endpoint to confirm that it is valid and to get the claims of the full JWT token.
It is tempting to use JWT tokens because they have all the claims encoded in without another lookup. Its also more risky because you can’t revoke them. They also potentially expose another security risk in that they reveal the internal claims of the token to the logged in user.
My example will work with the assumption that I will get a reference token for requests and therefore have to setup a way to communicate with the introspective endpoint in my api. The introspective endpoint is used to validate reference tokens.
Before I show code I just want to show two examples of rest calls that happen in this process to help show that its not that complicated.
A useful one endpoint is the Discovery endpoint which gets all the identity server configuration. Lets pretend that my identity server url is ‘IdentityServerUrl’.
GET https://IdentityServerUrl/.well-known/openid-configuration
The response for this should be something like:
{
"issuer": "https://IdentityServerUrl",
"token_endpoint": "https://IdentityServerUrl/connect/token",
"revocation_endpoint": "https://IdentityServerUrl/connect/revocation",
"introspection_endpoint": "https://IdentityServerUrl/connect/introspect",
"scopes_supported": [
"openid",
"profile"
],
"claims_supported": [
"sub",
"name",
],
"grant_types_supported": [
],
"response_types_supported": [
],
}
I took out some of the parts that I don’t think are relevant. What is nice is that it defines:
issuer
: Which certificate the issuer is using.
token
: Where to get a token with your credentials.
revocation_endpoint
: Where to revoke a reference token.
introspection_endpoint
: Where to validate a reference token.
A rest call to the introspective endpoint could be something like this:
curl --location --request POST 'https://IdentityServerUrl/connect/introspect' \
--header 'Accept: application/json' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-raw 'token=1234&client_id=clientId&client_secret=mysecret'
The token parameter is the supplied reference token and the client_id and client_secret has been configured with IdentityServer to identify the API making the call.
So after all of this. This is all you need to do to make your API authenticate with IdentityServer4.
Install the following nuget package:
IdentityServer4.AccessTokenValidation
In your Startup.Cs ConfigureServices you need to add:
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.SupportedTokens = SupportedTokens.Reference;
options.TokenRetriever = request => TokenRetrieval.FromAuthorizationHeader()(request);
options.Authority = "https://IdentityServerUrl";
// Reference Tokens - will contact the introspection endpoint found in the discovery document to validate the token
options.ApiName = "clientId";
options.ApiSecret = "mysecret";
});
In the Configure method you just need enable Authentication.
The reason that I went into so much detail is that only copying and pasting the code without understanding won’t help you if your configuration is wrong. In my experience it’s often initially wrong and so its important to understand that it isn’t magic.