Provider recipes
Every provider below is configured through Spring Boot’s own
spring.security.oauth2.client.registration.*. What follows is only the part that is
specific to each one, and each entry exists because it caused a real failure.
1. Google
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
Endpoints, scopes and the user-name attribute all come from CommonOAuth2Provider. Two
things to get right:
The redirect URI must be https. Google rejects http for anything that is not
localhost, so a deployment registers the https callback:
https://app.example.com/login/oauth2/code/google
A client builds its redirect URI from the request it was reached on. Reach the same
application over http and it sends an http URI that Google has never seen, and the login
dies with redirect_uri_mismatch. Behind a TLS-terminating proxy, either make sure forwarded
headers are honoured, or pin it:
spring:
security:
oauth2:
client:
registration:
google:
redirect-uri: https://app.example.com/login/oauth2/code/google
The principal name is the sub claim — a stable, never-reassigned, entirely unreadable
number. That is the right thing to key on and the wrong thing to show a human; see
the approval gate for how the two are kept apart.
2. GitHub
spring:
security:
oauth2:
client:
registration:
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope:
- read:user
- user:email (1)
uniauth:
oauth2:
github:
fetch-email: true (2)
| 1 | CommonOAuth2Provider defaults to read:user alone, which is enough to sign a user in
and not enough to learn an address. |
| 2 | GitHub keeps addresses on a separate endpoint, so there is no email until something asks
for one. This switches on GithubEmailOAuth2UserService, which makes that second call. |
GitHub is not OpenID Connect: no ID token, no claims, a bare OAuth2User. If your code
branches on having claims, branch on AuthProvider.oidc() rather than on the brand.
|
The adapter takes the account’s primary verified address and reports it as verified. It
deliberately prefers that over the |
A GitHub OAuth App allows exactly one callback URL, so pick the https one for a deployment and use a second app for local development.
3. Microsoft (multi-tenant)
uniauth:
oauth2:
microsoft:
multi-tenant: true
A multi-tenant Entra ID application issues ID tokens whose iss contains the caller’s
tenant, so Spring’s exact-issuer check rejects every tenant but the configured one.
MicrosoftMultiTenantIdTokenValidator does not reimplement validation. It hands Spring’s
own OidcIdTokenValidator a registration copy with the issuer removed — Spring skips its
issuer check when that is null — keeping every other check intact, then applies the
tenant-template issuer rule itself. It also checks the issuer before delegating, because
reading an unparseable iss throws and the delegate reads it first.
The adapter applies only to registrations detected as Microsoft, so switching it on cannot weaken a Google or Okta login sharing the same application.
4. Apple: unsupported, on purpose
Apple requires a generated client secret — an ES256 JWT, signed with a key from the
developer portal, with a limited lifetime. ClientRegistration.Builder takes a String.
Supporting Apple therefore means either a background task rewriting the registration or a
fork of the client-registration machinery, and both are worse than saying no. This stays
unsupported until Spring supports a non-static client secret.