Authentication & Authorization
There are a few key components that make Authorization & Authentication work.
Authentication Service (Tokens)
Auth is responsible for issuing tokens. Tokens are what users receive when they log in to the app. In Infrastructure/Auth, you’ll find the TokenService service, which exposes the methods GetTokenAsync and RefreshTokenAsync.
GenerateJWTToken adds roles and claims to the JWT token before it is signed and generated. Two important claims are the user & tenant Id.
GenerateRefreshToken creates a random string which serves as the long-expiry refresh token. This value is persisted with the ApplicationUser whenever a new login occurs.
The TokenResponse contains both the JWT auth token and refresh token. The values for expiration time are set in appsettings.json. By default, the JWT token expires after 30 minutes. The refresh token expires after 14 days. It is the client’s duty to store the refresh and auth token. When a 401 unauthorized response occurs, instead of having the user re-enter credentials, a new JWT auth token can instead be obtained by sending the refresh token value. This is implemented already in the Vue / React projects.
Current Tenant User Service
CurrentTenantUserService is a scoped service; it has values for TenantId, UserId, and ConnectionString, and a SetTenantUser method. This method is fired on every request by middleware, TenantResolver.
CurrentTenantUserService is found in WebApi/Services and has access to the HttpContext object. This service will set the tenant id on every request and if a bearer token is present, will also set the user id. These values will be available for the rest of the request lifecycle. The CurrentTenantUserService also plays a role in multi-tenancy, providing the tenant ID for query filters that run in DB contexts.
A ConnectionString property is only present when choosing multi-database as the multi-tenancy option. In a single-tenant setup, the classes are named ‘CurrentUser’ and don’t track the TenantId.
Identity Service
The Identity Service contains methods for managing users, updating profiles, and forgot / reset password. Data operations are handled with UserManager, a service provided by ASP Identity.
ApplicationUser is the main user class, which inherits from IdentityUser provided by ASP Identity.
Restricting API Controllers
Access control is the responsibility of the API controllers and can be easily handled with [Authorize] attributes.
To allow anonymous access add the [AllowAnonymous] attribute above the controller or specific endpoint. The TokensController is an example of an endpoint that allows anonymous access. When sending an anonymous request, a tenant ID must be present as a request header.
Endpoints require authorization by default. On authenticated requests, the tenant & user Id are read as claims from the token.
You can specify which roles can access a particular endpoint, for example: [Authorize(Roles = “root, admin”)]. The boilerplate has four roles: root, admin, editor, & basic which you can customize as needed. The root role is omitted in a single-tenant setup.
Identity Configuration
ASP Identity is registered in ConfigureApplicationServices found in WebApi/Extensions.
When ASP Identity is added to services, BaseDbContext is specified as the main context for identity. BaseDbContext inherits from IdentityDbContext. The main user class is ApplicationUser which inherits from IdentityUser, found in Infrastructure/Identity.
JWT Settings are also configured in ConfigureApplicationServices. Certain JWT parameters such as the key and duration are defined in appsettings.json.
In a single-database setup, there is no need for a separate BaseDbContext. Instead, the ApplicationDbContext is specified as the main context for identity.
Next Steps
Next we’ll take a close look at how multi-tenancy works.