Signing in with a Google account
An OIDC door is declared, and the decorator mounts its route, exchanges the token and sets the cookie. What is left to write is the decision: returning `None` REFUSES.from bretzel import auth, oauth
@auth.door(oauth.OIDC(
name="google",
issuer="https://accounts.google.com",
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
))
def way_in(profile) -> str | None:
"""The ONLY filter between “this person has a
Google account” and “this person comes into my
app”. Without it, the door is open to the whole
planet."""
if not profile.email.endswith("@mycompany.com"):
return None
return profile.email # the identifier kept
`@auth.door` STACKS: two doors can end at the same function, which is the common case when one accepts Google AND Microsoft. `oauth.OAuth2` covers the providers with no OIDC, where the three URLs are given by hand.Without OAuth: the identity source
`@auth.source` says WHERE an identity can come from — an API token, a header set by a trusted proxy, a home-made session. The function returns an identifier, or `None`.@auth.source
def from_the_token(request) -> str | None:
token = request.headers.get("x-api-key")
return accounts.by_token(token) # or None
# After a password check, over to you:
auth.login(user.id)
auth.logout()
auth.user_id() # str | None
auth.is_authenticated() # bool
The scope that depends on it
`UserState` is the only one of the four server scopes that demands an identity. That is what made the split confusing: an app resolving its own user, without going through `auth`, received a 401 on touching that scope.class Preferences(UserState):
theme: str = field(default="light")
# Readable as soon as `auth.user_id()` returns something.
Preferences().theme = "dark"
What is NOT shipped
No sign-in page supplied, no password handling, no roles and no permissions, no SAML. And not Apple: its `client_secret` is an ES256 JWT, hence a cryptographic dependency the framework refuses to add for one provider.`examples/auth` shows the four ways in side by side, and it runs.