The Auth Repository is where the User Auth information is persisted, e.g. an RDBMS (OrmLiteAuthRepository).
When the User is Authenticated, the User Info from the IAuthRepository
is used to populate the Users Session. Sometimes the IAuthRepository
contains the Users password and is what’s used to authenticate the user, e.g with:
- CredentialsAuthProvider
- BasicAuthProvider
- DigestAuthProvider
Other times, e.g. with OAuth Providers it just persists the User Info collected when they’ve authenticated with the OAuth Provider, which is merged with along with any other OAuth Provider the user has authenticated with. This information is used to populate the Users Session when the user has successfully registered with any AuthProvider.
The purpose of Authenticating is to populate an Authenticated Typed Users Session which is what’s stored in the Caching Provider that’s referenced by the ss-id/ss-pid Cookies. All runtime Auth Validators, e.g [Authenticate]
, [RequireAnyRoles]
uses the ss-id/pid on each Request (primarily from Request Cookies but also available from HTTP Headers, QueryString or IHasSessionId
Request DTOs) to first retrieve the Users Session from the registered Caching Provider which [Authenticate]
(and all other auth attrs) uses to verify the User has an Authenticated Session. The [RequireAnyRoles]
or permission attrs is validated using the HasRoles/HasPermission methods on the Users Typed Session (e.g. AuthUserSession
) to validate whether the User has the specified role/permission, unless the IAuthRepository
implements IManageRoles
in which case it looks up whether the User has the specified role in the Auth Repository - which is the only time the Auth Repository is used outside of Authentication.
I recommend JWT’s and have started using them a lot because it can greatly simplify Authentication for Services that need it since it essentially encapsulates the Users Session (partially with most essential info) in a single Token (i.e. JSON Web Token) which is an alternative to populating the Users Session from the ss-id/ss-pid Cookies as it’s instead populated entirely from the JWT Token (so doesn’t require Services to have either a Caching Provider to store Sessions or a IAuthRepository
to persist User Info). Authentication is taken care of by the JWT Signature which verifies that the token was created with someone with access to the Auth Key (i.e. the Service issuing JWT Tokens) which is how you can trust the info in the JWT Token.
I effectively think of JWT’s as a format for wrapping an Authenticated Users Session, this is ideal in Micro Services as there only needs to be a single “Auth” Service that needs to have Auth Providers / Auth Repositories and Caching Provider configured which authenticates the User, all other Micro Services will only need to validate the token which it can configure with just:
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new [] { new JwtAuthProviderReader(AppSettings) }));
Without needing to any have access to any other dependencies.
If the client Authenticates by sending a Authenticate
Request DTO (e.g. Username/Password credentials) then the JWT for the Users Session is returned in AuthenticateResponse
which if JwtAuthProvider
is registered will return the JWT Token in AuthenticateResponse.BearerToken
, if the Authenticate
request is sent with UseTokenCookie=true
then the JWT Token is also set the in the ss-tok
Cookie which automatically configures the Service Client to send authenticated requests using JWT on subsequent requests.
If Authenticating via OAuth then the client isn’t using the Authenticate
Request DTO and can instead convert their Authenticated User Session into a JWT Token with a call to ConvertSessionToToken
Service, e.g:
fetch("/session-to-token", { method:"POST", credentials:"include" });
Manually Creating JWT Auth Tokens
There’s a lot of flexibility in JWT’s which can also be created manually using just the registered JwtAuthProvider
which is handy if you have specific Auth Requirements or would like to impersonate a user:
var jwtProvider = (JwtAuthProviderReader)
AuthenticateService.GetAuthProvider(JwtAuthProvider.Name);
var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm);
var payload = JwtAuthProvider.CreateJwtPayload(new AuthUserSession
{
UserAuthId = "1",
DisplayName = "Test",
Email = "test@email.com"
}, "manual-jwt", TimeSpan.FromDays(14));
var token = JwtAuthProvider.CreateJwtBearerToken(header, payload,
data => JwtAuthProviderReader.HmacAlgorithms["HS256"](fallbackAuthKey, data));
Which you can configure in your Service Clients with:
var client = new JsonServiceClient(BaseUrl) { BearerToken = token };
So if you’re thinking about Stateless Sessions I’d recommend that you consider encapsulating them in JWT’s since it’s a popular industry standard format and there’s already a lot of support for them in ServiceStack and Service Clients.