Apricot Framework

Authentication

Why one section covers both directions, what the three packages contain, how a token is obtained and reused, and whose authority it carries.

A microservice authenticates in two directions. It validates the tokens it is given, and it presents tokens to the services it calls. Both are configured from one Authentication section here, because in practice they name the same provider and are deployed together.

The outbound half asks a second question: whose authority the token carries. The client credentials grant answers "this service"; token exchange answers "whoever this service is serving". Both are available at once and are chosen per call site.

Packages

PackageContains
ApricotFramework.Authentication.AbstractionsThe contracts alone: what a caller asks, what comes back, how it fails. Zero dependencies.
ApricotFramework.AuthenticationThe client credentials and token exchange grants. Zero dependencies.
ApricotFramework.Authentication.AspNetCoreJWT bearer validation, configuration binding, registration.
ApricotFramework.Authentication.ErrorDefinitionsAnswers authentication failures as problem+json.

Reference Abstractions from a client library — a gRPC, REST or messaging client — that needs a token presented but has no business knowing how one is obtained. It cannot reach the implementation, and it does not move when the implementation does.

Reference the core from the host that actually obtains tokens. It has no dependencies either — HttpClient and System.Text.Json are both in the shared framework — so a console or worker process can obtain tokens without referencing ASP.NET Core.

Obtaining a token

A token request needs an endpoint, and the endpoint comes from the provider's own metadata rather than from configuration. Two things about that document are checked before it is used:

  • the issuer it claims must be the authority that was asked for it, and
  • the token_endpoint it names must be on the same host.

Without the second check, a substituted or tampered metadata document names an endpoint of its own and the client secret is sent to whoever answers there. Both checks are why the authority is the only URL in configuration.

What is obtained is then reused. A token is cached until its stated expiry less a small margin, so one handed out is never about to expire in flight, and the discovered endpoint is cached for an hour. A cold cache under load makes exactly one token request: concurrent callers for the same credentials and scopes join the request already running rather than starting their own.

Note

The cache is process-local. Each instance of a service obtains its own tokens, which needs no shared infrastructure and puts no credential anywhere another host can read. Registering an ITokenCache before AddClientAuthentication replaces it.

Which failures are whose

A failure to obtain a token for an onward call is a fault of the service holding the credentials, never of whoever called it. Answering 401 would tell the caller to re-authenticate, which cannot help, and would record a service fault as a client error. TokenRequestException.Reason is what separates the case where waiting helps from the case where a person has to change something — see Error definitions.

On this page