Skip to content

Features

This page covers what a client can do, how people sign in to it and out of it, and what happens to their accounts over time.

How Who Approved
Added A manager, in /manage, which shows the secret once. Yes
Handshake A person completes /handshake, and masks returns the credentials to the app server to server. Yes
Self-registered The app, over dynamic registration, within the tenant’s ceiling. No
Metadata document The app, by using the URL of a document that describes it as its client_id. No

Only an approved client may hold a masks: scope, sign in as itself, receive a delegation, or name resources it serves, since a resource trusts the tokens issued for it. A self-registered client that names resources is refused. A client grants required_scopes always and allowed_scopes when asked. Archiving a client stops it signing anyone in and keeps its record.

An app that has never registered can use the URL of a JSON document it publishes as its client_id, as MCP clients do. masks fetches the document the first time the URL arrives, and registers the client as self-registered.

{
"client_id": "https://app.example.com/oauth/client.json",
"client_name": "Example App",
"redirect_uris": ["https://app.example.com/callback"],
"scope": "openid profile"
}
  • The URL is https, has a path, and carries no fragment, credentials, or . and .. segments.
  • The document names its own URL as client_id, is at most 5KB, and holds no client_secret. masks fetches it under the same rules as every other address it calls, so a private address is refused.
  • The client authenticates with PKCE alone or with private_key_jwt.
  • masks keeps the document for as long as its Cache-Control allows, between five minutes and a day, and for an hour when it gives no max-age. Then masks fetches it again.
  • A document that cannot be fetched or is refused is not fetched again for five minutes, and the client cannot sign anyone in until it is accepted.
  • A manager can archive the client to refuse it. Approving it keeps its redirect URIs, scopes, and keys, and later versions of the document change only its name, links, and logo.

Discovery sets client_id_metadata_document_supported to true while the tenant allows dynamic registration. With registration off, masks fetches no documents.

token_endpoint_auth_method
client_secret_basic The secret in a Basic Authorization header. The default.
client_secret_post The secret in the form body.
private_key_jwt An assertion signed with the client’s own key, checked against its jwks or jwks_uri.
none A public client, which proves itself with PKCE.

masks stores only a hash of a secret, and refuses a client that authenticates by a method other than the one it registered. A private_key_jwt assertion is accepted once and expires within an hour. An unknown key makes masks fetch the jwks_uri again, so a client can rotate keys without telling it.

masks asks each person once before a client receives anything. It asks again when the client asks for more scopes or resources, passes prompt=consent, or sends authorization details the person has not approved.

  • Approving a handshake is the approver’s consent, and nobody else’s.
  • A manager can turn consent_required off for an approved client, such as a first-party app. A self-registered client always asks.
  • A manager can set a client’s consent lifetime, from five minutes to 400 days. Once a consent is that old, the person is asked again. Without a lifetime, a consent lasts until it is revoked.

A public client sees the person’s own identifier as sub. A pairwise client sees one derived for its sector, the host of its redirect URIs, so two sectors cannot match their people. A client with redirect URIs on more than one host registers a sector_identifier_uri that lists them all.

A service that acts for no person, such as a nightly job, uses the client_credentials grant:

Terminal window
curl -u "$CLIENT_ID:$CLIENT_SECRET" https://acme.auth.example.com/token \
-d grant_type=client_credentials \
-d scope="xixo:catalog:read"

A manager enables it for an approved client. The token names the client as sub, carries no refresh token, and never holds a scope that acts for a person, such as openid or masks:manage.

A sign-in uses the organization’s policy, the client’s, the tenant’s default, or the built-in one, in that order. /manage edits them.

Setting Default
first_factors password, passkey, provider How a person proves who they are. Also accepts email_code.
second_factors otp, passkey, backup_codes Also accepts email, sms, and trusted_device.
second_factor_required off Ask for a second factor at every sign-in.
password_minimum 8 Minimum password length.
refuse_common_passwords on Refuse passwords on a list of about 47,000 common ones.
providers every provider Which providers to offer.
signup off Let people create their own accounts.
confirmation none How a new account is confirmed: none, code, link, or approval.
email_domains any The address domains signup and provider sign-in accept.

A policy also refuses breached passwords and steps up risky sign-ins. A factor the policy does not list is hidden and refused. The tenant’s default always keeps a password or a passkey, so managers are never locked out. Whatever the policy says, a manager must set up an authenticator app or a passkey as a second factor.

Factor
Password Stored as a bcrypt hash, and checked against the policy’s minimum and common passwords.
Passkey WebAuthn. It counts as a second factor too when the authenticator verified the person.
Provider An account at Google, Okta, a SAML identity provider, and others. See SSO / SAML.
Emailed code A six-digit code sent to the account’s address, with no password. See signing in with an emailed code.

When the policy offers passkeys and the browser supports passkey autofill, the sign-in field lists the person’s passkeys among its suggestions. Choosing one signs in without typing a nickname or address.

masks names each passkey after its authenticator from the FIDO Metadata Service, and marks one the service reports as compromised. A passkey whose signature counter fails to advance is treated as copied, and its sign-in is refused.

A policy that offers Emailed code shows Email me a code after the person identifies, or only that button when it offers no password. Since the tenant’s default keeps a password or a passkey, offer a code alone on a policy for the apps that want it.

  • The code has six digits, lasts ten minutes, and allows five attempts. Another can be sent after 30 seconds, within the account’s rate limit.
  • An address or nickname with no account gets the same screen and no mail, so the form does not reveal who has an account. Neither does an account that has reached its limit of codes.
  • An account that has not accepted its invitation gets no code, and neither does one with a password and an unconfirmed address. This stops someone from signing up with another person’s address, setting a password, and waiting for that person to confirm the address by signing in with a code.
  • Signing in with a code confirms the address of an account with no password.
  • Under a policy that hides who has an account, the address is proven first.
  • The code proves the inbox, so it records otp and never counts as a second factor. The email second factor is not offered after it, because both would come from the same inbox.
Factor
Authenticator app A TOTP code. Recorded as otp in amr.
Passkey A registered passkey.
Backup codes One-time codes, for when the other factors are lost.
Email code A six-digit code sent to a confirmed address. Recorded as otp.
Text message code A six-digit code sent through the tenant’s SMS adapter. Recorded as sms.
Trusted device The person enters a code shown on the new sign-in into the account page of a device they trusted.

Each person turns email and text message codes on from the account page once the address is confirmed. Once on, a code is asked for at every sign-in, under any policy, as an authenticator app is. Changing the address turns its codes off, and so does a password reset through an emailed link. An email code does not confirm a sign-in whose first factor was a provider.

After a second factor from an authenticator app, a passkey, or a sent code, the person can ask masks to trust the device. The second factor is then skipped on that device for 30 days, or until the device is signed out.

A device that cannot run a browser, such as a television or a CLI, uses the device grant. It asks /device_authorization for a code, shows the person the code and /device, and polls /token until the person approves on another device.

Poll response Do
authorization_pending Keep polling.
slow_down Add five seconds to the interval.
access_denied Stop. The person declined.
expired_token Request a new code. Codes last fifteen minutes.

A user code is eight letters with no vowels, such as BCDF-GHJK. Case and dashes are ignored.

An app sends the browser to /logout, the end_session_endpoint in discovery:

GET https://acme.auth.example.com/logout
?id_token_hint=eyJ…
&post_logout_redirect_uri=https://app.example.com/signed-out

post_logout_redirect_uri must be one the client registered. A GET without an id_token_hint for the signed-in person shows a confirmation screen first, so a link on another site cannot sign someone out.

When a session ends, masks posts a signed logout+jwt to the backchannel_logout_uri of every app the person used in it. masks tries each delivery five times, and records one that still fails on the person’s activity. masks never posts to a private address for a self-registered app.

A session is one signed-in browser. A device is the browser itself, known by a cookie that lasts 400 days.

Action Ends
Revoke a session That sign-in.
Sign a device out Every session and token on it, and its remembered second factor.
Sign an actor out Every session and refresh token on every device.
Block a device Every request from it, before any password is checked.

/manage also lists devices that never finished signing in, so they can still be blocked.

A session lasts 14 days by default. A sign-in policy changes this under Sessions.

Setting Effect
Lifetime A session started under the policy expires this long after signing in. An app covered by the policy asks for the password again in any older session.
Idle timeout A session started under the policy ends after this long with no request, and masks records session.expired. An app covered by the policy asks for the password again after a gap this long.

Both run from 5 minutes to 400 days, and the idle timeout is shorter than the lifetime. A refresh token issued in a session that either setting bounds stops working when the session ends, including when the person signs out. A session with neither setting leaves refresh tokens to their own lifetime.

An organization is a customer inside a tenant, whose members each hold a role there. An app that asks for the organization scope signs a person in as a member of one. See organizations.

A manager suspends, restores, or deletes an actor in /manage, and an identity provider does the same over SCIM. Suspending signs the actor out everywhere and refuses every sign-in until a manager restores them. Deleting signs them out everywhere, tells apps that registered for back-channel logout, and removes their passkeys, consents, connected accounts, and photo. Nobody can suspend or delete the last manager.

A tenant can suspend accounts nobody uses, and later delete them. Under Idle accounts in /manage, Suspend and Delete each take a period, and either can be left at Never. When both are set, deleting comes later than suspending.

  • Signing in, and an app refreshing a token for the person, both count as using the account.
  • masks emails a warning 30 days before each step, and takes the step no sooner than 30 days after its warning. Turning the settings on or changing them gives every account a fresh 30 days.
  • Signing in before a suspension keeps the account. Once suspended, only a manager can restore it, and the warning before deletion says so.
  • With Suspend set, only accounts suspended for being idle are deleted. With Suspend at Never, an idle account is deleted directly. An account a manager or an identity provider suspended stays until they decide.
  • An account with no confirmed email address cannot be warned, and follows the same schedule.
  • The last manager, accounts provisioned over SCIM, and invitations nobody has accepted are never touched.
  • A daily job does the work, and records each warning, suspension, and deletion as an event.

A person downloads everything masks holds about them as a JSON file from Download your account on their account page.

The file holds their profile, which factors they use and when each was added, their passkeys, organizations and roles, connected accounts and what each app was allowed to do with them, the apps they consented to, their devices, and every event about them that the tenant still keeps. It holds no password hash, authenticator secret, backup code, token, or key.

Each download is recorded as account.exported, and the person is emailed unless they turned off the Account group under Emails we send you. A person can download their account five times an hour.

A person deletes their own account at the bottom of their account page, by typing its nickname or email. The last manager and an account provisioned over SCIM cannot delete themselves.

Downloading and deleting both ask a person who signed in more than 15 minutes ago to sign in again first.