Skip to content

Java 21 ยท Spring Boot 3.3

Working

Multi-Tenant Authentication Service

One auth microservice and one Keycloak deployment serving separate tenants

Registration, login, refresh rotation and a custom Keycloak SPI implemented

Overview

A Spring Boot auth microservice covering registration, password-grant login, refresh-token rotation, and profile-driven realm selection, with Bearer JWT verified against the provider JWKS through Spring Security Resource Server. Realm selection from the profile is the part that makes it multi-tenant: one deployment, separate tenants, no per-tenant fork.

The identity provider itself is extended with a custom SPI for one-time-password storage and REST issuance. OTP is where auth services usually leak: the codes get stored in plain text, compared with a normal string equality, or left replayable. Here they are hashed with a peppered SHA-256, compared in constant time, single-use, and rate limited.

Stack

Language
Java 21, Spring Boot 3.3
Identity provider
Keycloak, extended with a custom SPI
Protocols
OAuth2 / OIDC, JWT verified against JWKS
Token handling
Spring Security Resource Server
Data
MongoDB
Events
Kafka

Decisions Worth Explaining

  • Peppered SHA-256 with constant-time compare for OTP

    A one-time password is short and low-entropy, so the stored form has to be useless if the store leaks, and the comparison must not leak timing. Single-use plus rate limiting closes the replay and brute-force paths.

  • Realm selection from the profile, not the subdomain

    Deriving the tenant from the request host couples auth to DNS layout. Driving it from the profile keeps one deployment serving tenants that may share a hostname.

  • A provider SPI rather than OTP in the application

    Putting OTP issuance in the identity provider keeps it available to every client of that provider, not only to this service.

What Is Not Done

  • Password-grant is a deprecated OAuth2 flow; it suits a first-party client but is not the right default for third-party ones.
  • No load test of the OTP rate limiter under concurrent issuance.