User Authentication
PocketBase ships with a complete authentication system out of the box: email/password login, OAuth2 providers (Google, GitHub, and more), email verification, password reset, one-time passwords (OTP), and multi-factor authentication (MFA) — no extra services required.
Two kinds of login: app users and superusers
“PocketBase login” means one of two things, and they use different collections:
| App users | Superusers (dashboard admins) | |
|---|---|---|
| Collection | users (or any auth collection you create) |
_superusers |
| Where they log in | Your app, through the SDK | The dashboard at https://<instance-name>.pocketbasecloud.com/_/ |
| Access | Whatever your API rules allow | Everything — rules are bypassed |
There is no default superuser login in PocketBase. A self-hosted
instance prints a one-time installer link on first start, or you create one
with ./pocketbase superuser upsert EMAIL PASS. On PocketBase Cloud every
instance is created with a platform-managed superuser — your account email
plus a generated password, shown on the instance page and by
pbc pocketbase info --name <instance>. Forgot it? Reset it without the old
password: see Upserting a Superuser Credential.
Superusers can also authenticate from code, for scripts and server-side jobs:
await pb.collection("_superusers").authWithPassword("[email protected]", "password");
Never ship superuser credentials to a browser or mobile app — use them only on a server you control.
Auth collections
Users live in auth collections. Every instance starts with a built-in
users collection, and you can create additional ones (e.g., staff) if you
need separate user types.
Email / password auth
Register a user
await pb.collection("users").create({
email: "[email protected]",
password: "s3cr3t-password",
passwordConfirm: "s3cr3t-password",
});
Log in
const authData = await pb
.collection("users")
.authWithPassword("[email protected]", "s3cr3t-password");
console.log(pb.authStore.isValid); // true
console.log(pb.authStore.token); // JWT
console.log(pb.authStore.record); // the user record
The SDK stores the token in pb.authStore (backed by localStorage in the
browser) and automatically sends it with every subsequent request.
Log out
pb.authStore.clear();
OAuth2 login (Google, GitHub, …)
Using the portal
- Open your instance’s admin panel at
https://<instance-name>.pocketbasecloud.com/_/ - Go to Collections → users → Options → OAuth2
- Enable a provider and paste in its client ID and secret
Using the CLI
pbc admin use https://<instance-name>.pocketbasecloud.com
pbc admin login
pbc admin auth users config # show authRule, oauth2, passwordAuth, mfa, otp, …
pbc admin auth users config --set 'oauth2={"enabled":true,"providers":[
{"name":"google",
"clientId":"<GOOGLE_CLIENT_ID>.apps.googleusercontent.com",
"clientSecret":"<GOOGLE_CLIENT_SECRET>"}]}'
--setreplaces that field entirely. To add a second provider, runpbc admin auth users configfirst and include every provider you want to keep in the JSON you send — otherwise the ones you omit are removed.
The same command edits the rest of the collection’s auth settings — for example, turning password login off once OAuth2 works:
pbc admin auth users config --set 'passwordAuth={"enabled":false}'
Then in your app the whole flow is one call:
const authData = await pb
.collection("users")
.authWithOAuth2({ provider: "google" });
PocketBase opens the provider’s consent screen, handles the redirect, and creates the user record on first login.
Tip: when registering the OAuth app with the provider, use
https://<instance-name>.pocketbasecloud.com/api/oauth2-redirectas the redirect URL.
Single sign-on (SSO)
For company SSO, use the OpenID Connect provider in the same OAuth2
list. Any OIDC-compliant identity provider — Okta, Auth0, Keycloak,
Microsoft Entra ID, Authentik — plugs in with its client ID, secret, and
auth/token/userinfo URLs, and your app calls authWithOAuth2 exactly as
above. PocketBase has no SAML support; if your identity provider only speaks
SAML, put an OIDC bridge (Keycloak, Authentik) in front of it.
One-time passwords (OTP)
OTP login emails the user a short code instead of asking for a password — useful for passwordless sign-in. Enable it in the dashboard under Collections → users → Options → One-time password (OTP), and make sure mail settings are configured so the code can be sent.
// 1. email a code to the user
const { otpId } = await pb.collection("users").requestOTP("[email protected]");
// 2. exchange the code the user typed for an auth token
await pb.collection("users").authWithOTP(otpId, "123456");
requestOTP returns an otpId even when the email doesn’t exist, so the
endpoint doesn’t leak which addresses have accounts. A successful OTP login
also marks the email as verified. Short numeric codes can be guessed, so for
anything sensitive pair OTP with a second factor (below) rather than using it
alone.
Multi-factor authentication (MFA)
MFA requires two different auth methods in a row — for example a password
and then an emailed OTP. Enable OTP and Multi-factor authentication
under Collections → users → Options. The first login then fails with an
mfaId, which you pass to the second method:
try {
await pb.collection("users").authWithPassword("[email protected]", "s3cr3t-password");
} catch (err) {
const mfaId = err.response?.mfaId;
if (!mfaId) throw err; // wrong password or another error
const { otpId } = await pb.collection("users").requestOTP("[email protected]");
const code = prompt("Enter the code we emailed you"); // your own UI here
await pb.collection("users").authWithOTP(otpId, code, { mfaId });
}
Editing OTP or MFA from the terminal works too —
pbc admin auth users configshows theotpandmfafields. Because--setreplaces a field entirely, copy the current JSON and change only what you need.
Email verification and password reset
PocketBase generates the verification and reset flows for you:
// send a verification email
await pb.collection("users").requestVerification("[email protected]");
// send a password reset email
await pb.collection("users").requestPasswordReset("[email protected]");
Email templates and the sender address can be customized in the admin panel under Settings → Mail settings, or from the terminal:
pbc admin settings mail # current SMTP config
pbc admin settings mail set '<json>'
pbc admin settings mail test [email protected] # send a test message
The verification and reset templates live on the auth collection itself, so
they’re edited with pbc admin auth users config --set 'verificationTemplate={…}'.
Protecting data per user
Combine auth with API rules to
scope records to their owner. A common pattern is an owner relation field on
the collection with rules like:
@request.auth.id != "" && owner = @request.auth.id