Multiple components work together to form the authentication and authorization flows in Microbus. A two-token architecture separates long-lived bearer tokens from short-lived access tokens, providing a clear boundary between external identity and internal authorization.
To get started, the client submits credentials to an authenticator microservice. In the simplest form, credentials are a username and a password obtained from the user via a web form. If the credentials are valid, a bearer token is issued in the form of a JWT and returned back to the client.
Microbus does not include authenticators out of the box. The login example microservice demonstrates how such a microservice may look like when the client is a browser. A Set-Cookie response header returns the bearer token to the browser, which in turn sends it back with all consecutive requests in a Cookie request header. The cookie is named Authorization to allow the authorization middleware to easily locate it.
Bearer tokens are long-lived JWTs signed by an external identity provider or by the bearer token core microservice. The bearer token microservice uses Ed25519 key pairs and exposes a JWKS endpoint that publishes its public keys, allowing any party to verify the token’s signature without sharing a secret.
Now that the client is in possession of a bearer token, it’s expected to be included in the header of consecutive requests. The authorization middleware examines the HTTP request headers for a bearer token in the Authorization: Bearer header or in a Cookie named Authorization.
Cookie: Authorization=<JWT>
Authorization: Bearer <JWT>
When a bearer token is found, the middleware exchanges it for a short-lived access token in a multi-step process:
iss claim and the kid headeriss claim identifies the token issuer microservice. The middleware fetches the issuer’s public keys from its JWKS endpoint and caches them by kididp claim and instead sets the iss claim to microbus://access.token.coreAccess tokens use ephemeral Ed25519 key pairs that rotate automatically. Like the bearer token service, the access token microservice exposes a JWKS endpoint that aggregates public keys from all replicas, enabling any microservice to verify access tokens independently.
The connector of each microservice evaluates the claims in the access token to determine whether the request is allowed to proceed. Requirements are expressed as a boolean expression and specified during the definition of the endpoint, using the sub.RequiredClaims option when creating the subscription.
For example, the option sub.RequiredClaims("groups.sales && (roles.director || roles.manager)") indicates that the endpoint is restricted to directors or managers only from the sales group. Requests by actors that do not satisfy these requirements will be denied with a 401 Unauthorized or 403 Forbidden error.
By default, 401 Unauthorized and 403 Forbidden errors are returned to the client in the form of an HTTP status code accompanied by an error message. The error page redirect middleware can improve user experience by redirecting to a more user-friendly page. Redirection is contingent upon the Sec-Fetch-Mode and Sec-Fetch-Dest request headers indicating that the user is using a browser to navigate to a new document, thus avoiding interfering with requests from single-page applications.
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
A 401 Unauthorized error indicates that the user is not logged in. The following redirects to a login page where the user can begin the authentication flow.
httpIngressProxy := httpingress.NewService()
httpIngressProxy.Middleware().Append("401Redirect", middleware.ErrorPageRedirect(http.StatusUnauthorized, "/login"))
A 403 Forbidden error indicates the user is attempting to access a page or API they are not authorized for. The following redirects to a dedicated error page.
httpIngressProxy.Middleware().Append("403Redirect", middleware.ErrorPageRedirect(http.StatusForbidden, "/access-denied"))