The problem
Most implementations of SMART App Launch v2.2 bury the launch context inside the JWT access token. The spec is explicit: patient, encounter, and need_patient_banner must be top-level fields in the token response JSON body, not claims inside the token itself.
{
"access_token": "eyJhbGciOiJSUzI1NiI...",
"patient": "GOLDEN-00441",
"encounter": "enc-441-br01",
"need_patient_banner": true
}
This matters because the SMART client cannot decode the JWT synchronously in all environments — particularly in EHR-embedded launch contexts where the client may not have access to the JWKS endpoint at launch time. The launch context must be readable without decryption.
Why it happens
Spring Authorization Server 1.x puts all extra claims inside the JWT by default. The SmartTokenResponseConverter in AJ Auth Server overrides this by extracting patient and encounter from the launch context stored at authorization time and injecting them directly into the OAuth2AccessTokenResponse map.
How AJ Auth Server handles it
The launch token is stored as an atomic single-use database INSERT at authorization request time. When the token endpoint fires, the converter fetches the launch context by opaque token, extracts patient and encounter references, and writes them to the response body — never inside the JWT payload.
PKCE S256 — the correct verifier entropy
The spec requires a minimum 43-character code verifier. AJ Auth Server generates a 96-byte (768-bit) random verifier, which is 3× the minimum. This matters because the code verifier must be unguessable across the lifetime of the authorization code (up to 10 minutes by default).