Authentication providers#
Choose the provider that matches where identity is established:
Local accounts support session, token, and hybrid applications.
OAuth and OpenID Connect support browser sign-in and account linking.
Google IAP verifies the assertion added by the IAP proxy for one exact audience.
API keys authenticate service clients from a digest-only application store.
Workload JWTs authenticate non-user services through a pinned issuer, audience, and JWKS endpoint.
Adding a provider makes its authentication mechanism available. Route policy
decides where it is accepted, and an application authorization_resolver
loads scopes, roles, capabilities, teams, and tenants for the verified
principal.
OAuth transaction and token protection#
The in-memory OAuth references require an OAuthTransactionProtector so
that the PKCE verifier, nonce, and refreshable provider tokens are not kept as
plaintext. The first-party AES-256-GCM protector supplies that port to the
transaction store and aggregate account store:
from litestar_security.providers.oauth import (
AESGCMOAuthTransactionProtector,
MemoryOAuthAccountStore,
MemoryOAuthTransactionStore,
OAuthTransactionProtectorKey,
)
protector = AESGCMOAuthTransactionProtector(
active_key=OAuthTransactionProtectorKey(
"v2",
application_secret_store.get_bytes("oauth-transaction-protector/v2"),
),
retained_keys=(
OAuthTransactionProtectorKey(
"v1",
application_secret_store.get_bytes("oauth-transaction-protector/v1"),
),
),
)
transactions = MemoryOAuthTransactionStore(protector=protector)
accounts = MemoryOAuthAccountStore(
provider="github",
client_id="github-client-id",
protector=protector,
)
The values returned by application_secret_store are application-owned,
exactly 32-byte key material from a KMS or secret store, never hard-coded
literals. During rotation, retain the previous key before making the new key
active, then remove it only after envelopes under the earlier version have
expired or been replaced.
An application may instead supply its own protector. Run
assert_oauth_transaction_protector_conformance()
against a fresh instance factory to verify the public protection contract.
OAuthAccountStore is the durable application boundary for provisioning,
exact identity linking, grants, retained tokens, refresh compare-and-swap, and
revocation retry staging. Implement each operation as one database transaction;
the library ships no ORM or database-specific adapter.
Provider confirmation#
POST /auth/oauth/{provider}/revalidate confirms that the browser still
controls the exact identity linked to the local account. It does not assert
fresh authentication and cannot issue a step-up credential.
POST /auth/oauth/{provider}/reauthenticate/{purpose} is available only for
providers implementing OAuthReauthenticationProvider and purposes present
in that provider’s OIDCReauthenticationPolicy mapping. OIDC reauthentication
uses max_age (zero forces authentication), requires signed auth_time,
and checks the configured ACR and AMR requirements before issuing a one-use,
purpose-bound StepUpCredential. GitHub account selection is not fresh
authentication and therefore cannot provide this capability.
Use discover_oidc_provider() or discover_google_oidc_provider() when the
application owns shared OIDCDiscoveryClient and JWKSProvider resources.
The returned provider owns only its OAuth HTTP client; closing it does not close
the shared discovery or JWKS resources.
Google IAP human, service account, and agent identities#
When Google Identity-Aware Proxy fronts an application used by both Google
Workspace users and non-interactive callers (such as Cloud Run service accounts,
Vertex AI Agent Engine reasoning engines, or GKE Workload Identity workloads),
GoogleIAPClaims exposes structured classification helpers so your
IdentityResolver[GoogleIAPClaims, User] does not have to parse sub
prefixes or email suffixes manually:
claims.normalized_subjectstrips the leadingaccounts.google.com:prefix added to Google-issued IAP assertions.claims.is_service_accountisTrueonly for Google-issued assertions (noexternal_identityorhosted_domain) whoseemailends withgserviceaccount.comor.gserviceaccount.com.claims.spiffe_idreturns the validatedprincipal://agents.global....,principalSet://agents.global...., orspiffe://...URI when present (andNonefor human users, service accounts, or GCIP external identities).claims.is_agent_identityandclaims.is_machine_principalclassify SPIFFE / Agent Engine workloads and combined non-human principals.
from litestar_security import IdentityResolution, InvalidCredentials, Principal
from litestar_security.providers.iap import GoogleIAPClaims
class IAPPrincipalResolver:
def __init__(
self,
*,
allowed_domains: frozenset[str],
allowed_service_accounts: frozenset[str],
allowed_spiffe_ids: frozenset[str],
) -> None:
self._allowed_domains = allowed_domains
self._allowed_service_accounts = allowed_service_accounts
self._allowed_spiffe_ids = allowed_spiffe_ids
async def resolve(self, claims: GoogleIAPClaims) -> IdentityResolution[dict[str, str]]:
if claims.hosted_domain in self._allowed_domains and claims.email:
user = {"id": claims.normalized_subject, "email": claims.email, "kind": "human"}
return Principal(id=claims.normalized_subject, display_name=claims.email, user=user)
if claims.is_service_account and claims.email in self._allowed_service_accounts:
user = {"id": claims.normalized_subject, "email": claims.email, "kind": "service_account"}
return Principal(id=claims.normalized_subject, display_name=claims.email, user=user)
if claims.spiffe_id in self._allowed_spiffe_ids and claims.spiffe_id is not None:
user = {"id": claims.spiffe_id, "kind": "agent"}
return Principal(id=claims.spiffe_id, display_name=claims.spiffe_id, user=user)
return InvalidCredentials()
API key Bearer extraction alongside JWTs#
By default, APIKeyConfig reads keys only from its dedicated request header
(such as X-API-Key). When CLI, SDK, or Model Context Protocol (MCP) clients
send prefixed API keys through Authorization: Bearer <prefix>_<key_id>_<secret>,
enable accept_authorization_bearer=True:
from litestar_security.providers.api_key import APIKeyConfig
api_keys = APIKeyConfig(
store=api_key_store,
identity_resolver=api_key_resolver,
pepper=api_key_pepper,
accept_authorization_bearer=True,
)
When accept_authorization_bearer=True is combined with
CompositeBearerConfig, ServiceTokenConfig, or LocalAuth Bearer
tokens in the same SecurityConfig, litestar-security automatically
routes Authorization: Bearer <prefix>_... credentials to the API key slot
while non-prefixed Bearer tokens continue through the JWT slot, and projects
both the header APIKey scheme and APIKeyBearer HTTP Bearer scheme into
OpenAPI.