NativeOAuth2LoginService class
The OAuth2LoginService of phones and desktops: the app logs its user in by itself with an OAuth 2.0 or OpenID Connect provider (Keycloak, Google, Auth0, ...), keeps them logged in across restarts, and logs them out.
An app cannot keep a client secret (anyone can extract it), so it logs
in as a public client with the authorization code flow and PKCE (RFC
8252, "OAuth 2.0 for Native Apps"): login opens the provider's page
in the system's login window (a Safari sheet, a Chrome tab, the
default browser), the user logs in there (the app never sees the
password), the provider redirects back with a code, and the code is
exchanged for tokens. Everything that can be forged is checked: the
state against forged redirects, the iss of the redirect against
mixed-up providers, the PKCE verifier binds the code to this app, the
ID token's issuer, audience, times and nonce, and the user info's
subject. The user then is an OAuth2AuthenticationToken in the
SecurityContextHolder (so @PreAuthorize and the Feign interceptor
see them), the tokens are in the OAuth2AuthorizedClientService (the
SecretStoreOAuth2AuthorizedClientService on the platform's secure
storage), and an AuthenticationSuccessEvent is published.
restore brings the user back at startup from the stored tokens,
refreshing them when needed; logout revokes the tokens at the
provider (when it has a revocation_endpoint), forgets them, clears
the context and publishes a LogoutSuccessEvent. With DPoP it also
deletes the app's PlatformDPoPKey, so the next login is bound to a
new key.
A registration with native-sign-in=apple (NativeSignIn; the
default of the apple provider) signs in with Sign in with Apple's
sheet on iOS and macOS (appleIdSignIn) instead of the browser: the
sheet's state must come back, its identity token (from the
operating system, not from a TLS connection of the app) must verify
with Apple's keys (nativeIdTokenDecoder: the registration's
jwk-set-uri, issuer, audience = the client id, expiry) and carry the
nonce sent, and its sub must be the sheet's user. The code is then
exchanged at the registration's token-uri, which for an app must be
its own server: only a server can sign Apple's client secret (Apple's
own flow for apps: the app hands the code to its server, which checks
it with Apple and keeps the session). The name and e-mail Apple sends
on the first authorization only go into the user's info and are kept
in the login record (and carried to the next sign-ins of the same
user).
Apps use it through OAuth2LoginService: the package declares it as
the oauth2LoginService bean on Android, iOS, macOS, Windows and
Linux when a registration is configured, with the platform's
AuthorizationWindow (PlatformAuthorizationWindow on Android, iOS
and macOS, LoopbackAuthorizationWindow on Windows and Linux). A web
page gets the ServerOAuth2LoginService instead, where the server
logs the user in.
Spring has no counterpart: Spring Security's oauth2Login() logs
browsers in on a server. The checks are those of its
OAuth2LoginAuthenticationFilter,
OidcAuthorizationCodeAuthenticationProvider and OidcUserService.
- Implemented types
Constructors
-
NativeOAuth2LoginService({required ClientRegistrationRepository clientRegistrationRepository, required OAuth2AuthorizedClientService authorizedClientService, required SecretStore secretStore, required OAuth2AccessTokenResponseClient<
OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient, required OAuth2UserService<OAuth2UserRequest, OAuth2User> userService, required OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService, AuthorizationWindow? authorizationWindow, OAuth2AuthorizedClientManager? authorizedClientManager, OAuth2TokenRevocationClient? revocationClient, PlatformDPoPKey? dPoPKey, AppleIdSignIn? appleIdSignIn, Map<String, NativeSignIn> nativeSignIn = const {}, OidcIdTokenDecoder? nativeIdTokenDecoder, OidcIdTokenDecoder? idTokenDecoder, GrantedAuthoritiesMapper authoritiesMapper = const NullAuthoritiesMapper(), ApplicationEventPublisher? eventPublisher, SecurityContextHolderStrategy? securityContextHolderStrategy, Uri? baseUrl}) - A login service; the package's auto-configuration passes the beans.
Properties
-
accessTokenResponseClient
→ OAuth2AccessTokenResponseClient<
OAuth2AuthorizationCodeGrantRequest> -
Exchanges the code.
final
- appleIdSignIn → AppleIdSignIn?
-
Sign in with Apple's sheet (iOS, macOS), or
nullwhere there is none: then every registration logs in in the authorizationWindow.final - authentication → OAuth2AuthenticationToken?
-
The logged-in user's authentication, or
null.no setteroverride -
authenticationChanges
→ Stream<
OAuth2AuthenticationToken?> -
The authentication after each login, restore and logout (
null): for a UI that shows who is logged in.PrincipalNotifierandcontext.principalare usually simpler.no setteroverride -
Maps the user's authorities.
final
-
Opens the provider's login page and waits for the redirect back, or
null(then login throws).final -
Refreshes the tokens in restore; without one they are not
refreshed there.
final
-
Where the tokens are kept.
final
- baseUrl → Uri
-
The value of
{baseUrl}in the redirect URI templates.final - clientRegistrationRepository → ClientRegistrationRepository
-
The registrations.
final
- dPoPKey → PlatformDPoPKey?
-
The app's DPoP key, deleted at logout so the next login gets a
new one;
nullwhen the app has no PlatformDPoPKey (a key of its own is left alone).final - eventPublisher → ApplicationEventPublisher?
-
Receives the login and logout events, or
null.final - hashCode → int
-
The hash code for this object.
no setterinherited
- idTokenDecoder → OidcIdTokenDecoder
-
Decodes and checks the ID token.
final
- isLoggedIn → bool
-
Whether someone is logged in.
no setteroverride
- nativeIdTokenDecoder → OidcIdTokenDecoder?
-
Checks the identity tokens of the sheets, signatures included (a
JwkSetOidcIdTokenDecoderin the package's bean); without one a native sign-in is refused.final -
nativeSignIn
→ Map<
String, NativeSignIn> -
The registrations that sign in with a sheet of the system instead
of the browser, by id (NativeSignIn.of the properties).
final
-
oidcUserService
→ OAuth2UserService<
OidcUserRequest, OidcUser> -
Loads OpenID Connect users.
final
- revocationClient → OAuth2TokenRevocationClient?
-
Revokes the tokens in logout; without one they are not revoked.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- secretStore → SecretStore
-
Where the login record is kept (the same store as the tokens).
final
- securityContextHolderStrategy → SecurityContextHolderStrategy
-
Where the logged-in user is put.
final
- user → OAuth2User?
-
The logged-in user (OidcUser with OpenID Connect), or
null.no setter -
userService
→ OAuth2UserService<
OAuth2UserRequest, OAuth2User> -
Loads OAuth 2.0 users.
final
Methods
-
login(
String registrationId, {Map< String, String> additionalParameters = const {}}) → Future<OAuth2AuthenticationToken> -
Logs the user in with the registration
registrationId, in the system's login window, and returns their authentication.override -
logout(
{bool endSession = false, Uri? postLogoutRedirectUri}) → Future< void> -
Logs the user out: revokes their tokens at the provider (refresh
token first, when it has a
revocation_endpoint), forgets the tokens, deletes the dPoPKey (the next login makes a new one), clears the security context and publishes aLogoutSuccessEvent. Nothing happens when nobody is logged in.override -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
restore(
) → Future< OAuth2AuthenticationToken?> -
Brings back the user of the stored tokens and returns their
authentication;
nullwhen nobody is stored.override -
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Constants
- sessionKey → const String
- The key of the login record in the secretStore: which registration and user are logged in, and what is needed to show them offline.