Skip to content
taurasgPreparing
ENLT
Back

12 December 2025

Writing the authorization server instead of buying it

AltPro issues its own OAuth2 tokens from a service of its own — which is more work than a login form and buys one thing that matters.

The easy version of AltPro is one Spring Boot application with a login form, a session cookie and @PreAuthorize on the controllers. It works, it is a fraction of the code, and I did not build it.

The reason

A single application can always check the wrong thing. When the session and the domain live in the same process, "is this person logged in" and "is this person allowed" are two questions answered from the same object, and the day a second client appears — a mobile app, a script, another service — there is no seam to put a token boundary on. You add one, and it lives beside the cookie path rather than instead of it.

So there are two services:

  • altpro-auth — Spring Authorization Server. Issues OAuth2 and OIDC tokens. Keeps users, registered clients and consents.
  • altpro-api — a resource server that will not answer without a valid Bearer JWT and has no idea what a password is.

The React client is redirected to the issuer, comes back with an identity token, and calls the API with an access token. nginx routes /auth/* and /api/*, and both services share one MongoDB with no overlap in what they store.

What it actually bought

  • The API cannot be tempted into trusting a cookie, because it has never had one.
  • Adding a second client is registering a client, not designing a second way in.
  • A permissions mistake fails at a network boundary — a 401 from a service that has no reason to be lenient — rather than somewhere inside a request that had already been trusted.

What it cost

Two deployments, two sets of configuration, and a local development loop where the thing you are debugging is frequently the redirect rather than the code. The first afternoon was entirely issuer-uri mismatches.

Worth it here because the whole exercise was the boundary. If the brief had been "ship a task list", the login form would have been the right answer.

© 2026 Tauras Giedraitis · Kaunas, Lithuania · All rights reserved