Skip to main content

Authenticated API call

Every service applies the same checks in the same order.

Authenticated API call. The browser sends a request with a bearer token to the ingress, which routes by prefix to a service. The service's OIDC layer verifies the token signature, issuer and expiry against Keycloak's keys and answers 401 if it fails. The role filter checks the required role and the tenant and answers 403 if they do not match. The resource method then reads the caller from the verified token and uses the database.

The rules​

  • Verified token wins. The caller is the token's preferred_username claim. A request header that names another user is ignored when a token is present.
  • Roles come from the token. Realm roles are mapped to the names used by @RequiresRole. A caller who needs a role the token does not carry gets 403.
  • Tenant. A caller who is not platform-wide must prove a tenant claim that matches the tenant being addressed.
  • Headers are not an identity. Production services do not read X-User-Id, X-User-Role or X-Tenant-Id as identity for an unauthenticated request. A startup guard refuses to start a production service with header identity enabled.
  • Some checks are in code. Enrolment checks and moderator checks happen inside the resource or service. Not every endpoint checks that a record belongs to the caller.

The paths that skip the token check are listed in Public paths.

Sources: libs/common-models/src/main/java/com/rtih/startupos/common/security/{RoleEnforcementFilter,HeaderIdentityPolicy}.java, services/lms-service/src/main/resources/application.yml (quarkus.http.auth.permission), .agents/tasks/oidc-enforcement/finish/final-report.md.