howdy/auth/provider
External identity providers. Install one with auth.with_provider.
The built-in constructors in howdy/auth/providers cover Google, GitHub,
Facebook, Microsoft Entra, Apple and any OpenID Connect issuer
(providers/oidc). For anything else, custom takes the two steps of
an OAuth 2.0 authorization-code flow and leaves everything around them
(state, PKCE, nonce, cookies, linking, MFA and sessions) to Howdy.
Types
What to put in the provider’s authorization URL. Send redirect_uri and
state unchanged. challenge is a PKCE S256 code challenge: send it as
code_challenge with code_challenge_method=S256 if the provider
supports PKCE. nonce is for OpenID Connect providers; others ignore it.
pub type Authorization {
Authorization(
redirect_uri: String,
state: String,
nonce: String,
challenge: String,
)
}
Constructors
-
Authorization( redirect_uri: String, state: String, nonce: String, challenge: String, )
A returning callback, with state already checked. Redeem code at the
provider’s token endpoint with this redirect_uri and, if you sent a
challenge, verifier as code_verifier. An OpenID Connect ID token’s
nonce must pass nonce_matches.
pub type Exchange {
Exchange(
code: secret.Secret,
redirect_uri: String,
verifier: secret.Secret,
nonce_digest: String,
)
}
Constructors
-
Exchange( code: secret.Secret, redirect_uri: String, verifier: secret.Secret, nonce_digest: String, )
Who the provider says signed in, returned by a custom provider’s
verify.
subject is the provider’s stable, unique identifier for the account,
never an email address or anything else its owner can change: accounts are
linked by it. At most 255 bytes.
email is the address the provider reports, or empty. Howdy never
attaches a provider sign-in to an existing account because the addresses
match; the user links it from the account page. The address only matters
when the provider sign-in creates a new account, which needs
email_authoritative: set it only when the provider is the authority for
that address, as Google is for @gmail.com, not merely when it once
verified the address. Setting it wrongly lets anyone who can make an
account at the provider claim an address that is not theirs. When
unsure, leave it False: new users then register by email and link.
pub type Verified {
Verified(
subject: String,
email: String,
email_authoritative: Bool,
)
}
Constructors
-
Verified( subject: String, email: String, email_authoritative: Bool, )
Values
pub fn custom(
id id: String,
name name: String,
issuer issuer: String,
authorize authorize: fn(Authorization) -> String,
verify verify: fn(Exchange) -> Result(Verified, service.Error),
) -> Provider
A provider of your own. id names it in routes and cookies: lowercase
letters, digits and hyphens, at most 32. name is shown on sign-in pages.
issuer is the provider’s HTTPS URL; its accounts are recorded under it,
kept apart from every built-in provider and SSO connection, so changing it
later forgets every linked account. Two installed providers may not share
one.
authorize returns the URL to send the browser to. verify redeems the
code and returns the account; return Error(service.Unauthorized) for
anything the provider refuses or that fails to parse. Bound the size of
responses you read, and do not log them: they carry the user’s tokens.
Any provider access token is yours to discard; Howdy stores none.
let assert Ok(identity) =
auth.with_provider(identity, provider.custom(
id: "gitea",
name: "Gitea",
issuer: "https://git.example.com",
authorize: fn(request) {
"https://git.example.com/login/oauth/authorize?" <> uri.query_to_string([
#("client_id", client_id),
#("redirect_uri", request.redirect_uri),
#("response_type", "code"),
#("state", request.state),
#("code_challenge", request.challenge),
#("code_challenge_method", "S256"),
])
},
verify: fn(exchange) { gitea_account(exchange) },
))
pub fn nonce_matches(exchange: Exchange, nonce: String) -> Bool
Whether an ID token’s nonce claim is the one this sign-in sent.