Use for Volcano authentication and identity work including user accounts, email or password sign-up and sign-in, OAuth, sessions, anonymous users, password recovery, and private or per-user data.
Use for Volcano authentication and identity work including user accounts, email or password sign-up and sign-in, OAuth, sessions, anonymous users, password recovery, and private or per-user data.
Volcano Auth Skill
Role
Implement robust Volcano authentication journeys with session lifecycle correctness. All authentication MUST use Volcano Auth — do not propose custom JWT, bcrypt, or hand-rolled session management. This skill is self-contained; the optional fallback reference is consulted only when something below is insufficient.
Workflow
Implement sign-up/sign-in/sign-out with explicit UI loading/error/success states.
Restore the session on app startup with volcano.initialize().
Add onAuthStateChange listener and ensure cleanup on teardown.
Keep OAuth initiation in browser contexts only; validate error paths.
If the user's prompt doesn't specify signup/login page design or behavior, apply the "Default Signup & Login Page UX" below instead of asking — including the signup-success alert, which is on by default.
Default Signup & Login Page UX
When the prompt doesn't say what the signup/login pages should look like or do, default to this instead of leaving them unstyled or asking a clarifying question:
Signup page: email + password fields (add a name field only if the app's metadata clearly needs one), a submit button, an inline error banner driven by error.message, and a link to the login page.
Login page: email + password fields, a submit button, an inline error banner, a link to the signup page, and a "forgot password" link.
Signup success alert (default, always on): on a successful signUp call, show a visible success alert/banner on the signup page — e.g. "Signup successful! Check your email to verify your account." — before navigating away. Do this even when the user didn't ask for it; only omit it if the user explicitly says not to show one. A redirect (2–3s) after showing the alert is fine, but the alert must render first.
Service keys (prefix sk-) are server-only; using one in anonKey from a browser environment throws.
Email/Password
Sign Up
const { user, session, error } = await volcano.auth.signUp({
email: 'alice@example.com',
password: 'secure-password-123',
metadata: { full_name: 'Alice', avatar_url: '...' }, // optional
});
if (error) {
if (error.message.includes('already exists')) /* email taken */;
elseif (error.message.includes('password must')) /* strengthen — real messages: "password must be at least 15 characters", "...contain at least one uppercase letter", etc. */;
elseif (error.message.includes('invalid email')) /* validate */;
return;
}
// metadata is stored on user.user_metadata
Sign In
const { user, session, error } = await volcano.auth.signIn({ email, password });
if (error) {
if (error.message.includes('invalid email or password')) /* wrong creds */;
elseif (error.message.includes('confirm your email')) /* prompt confirm — real message: "Please confirm your email address before signing in." */;
elseif (error.message.includes('rate limit')) /* rate-limited — real message: "rate limit exceeded, try again later" */;
return;
}
// SDK auto-stores tokens in localStorage (browser) and schedules refresh.
Sign Out
const { error } = await volcano.auth.signOut();
// Clears local session and invalidates the refresh token server-side.
Session Management
Synchronous current user (cached)
const user = volcano.auth.user();
// Returns the cached User or null. Does not hit the network.
Restore session on app load (handles OAuth callback tokens too)
const { user, error } = await volcano.initialize();
// Returns the restored user, or null if no valid session exists.
Auth state listener
const unsubscribe = volcano.auth.onAuthStateChange((user) => {
if (user) showApp(user); elseshowLogin();
});
// Fires once immediately with current state, then on every change.// Always call unsubscribe() on teardown.
Manual refresh
const { session, error } = await volcano.auth.refreshSession();
// Tokens auto-refresh; call this only for explicit forced rotation.
OAuth / SSO
Providers
google, github, microsoft, apple.
Configure the provider (required before sign-in works)
OAuth providers live in volcano-config.yaml under auth.providers.oauth (a list) and are applied with config deploy:
redirect_url is required — omitting it fails config deploy with redirect_url is required. It is the Volcano callback (<apiUrl>/auth/oauth/<provider>/callback), not your app page: Volcano handles the provider round-trip, then returns your app to the URL from signInWithOAuth('<provider>', { redirectTo: '<app-url>' }) (the redirectTo option; defaults to the current page when omitted). Cloud form: https://api.<project>.volcano.dev/auth/oauth/<provider>/callback.
Combining email/password with OAuth: if both email/password signup and any OAuth/SSO provider are enabled, you must also set auth.email_verification.require_confirmation: true and configure SMTP (Mailpit locally, real SMTP in cloud), or config deploy fails with email/password signups and SSO cannot both be enabled unless require_email_confirmation is true and SMTP is configured.
Begin OAuth (browser only — throws on server)
volcano.auth.signInWithGoogle();
volcano.auth.signInWithGitHub();
volcano.auth.signInWithMicrosoft();
volcano.auth.signInWithApple();
// Generic form:
volcano.auth.signInWithOAuth('google');
// Return the browser to a specific app page afterward (defaults to the current page):
volcano.auth.signInWithOAuth('google', { redirectTo: `${window.location.origin}/dashboard` });
These redirect to the provider; on return, call volcano.initialize() on the callback page to consume the tokens from the URL.
// Createconst { user, session, error } = await volcano.auth.signUpAnonymous({
preferred_theme: 'dark', // optional metadata
});
// Convert to a full account (preserves the user.id and all owned data)const { user, error } = await volcano.auth.convertAnonymous({
email: 'alice@example.com',
password: 'secure-password-123',
metadata: { full_name: 'Alice' },
});
Email Verification
// After clicking the email link, the URL contains a token query param.const token = newURLSearchParams(window.location.search).get('token');
const { error } = await volcano.auth.confirmEmail(token);
// Resend if the user lost the emailawait volcano.auth.resendConfirmation('alice@example.com');
Password Recovery
// Always succeeds (even for unknown emails) for security.await volcano.auth.forgotPassword('alice@example.com');
// On the reset page:const token = newURLSearchParams(window.location.search).get('token');
const { error } = await volcano.auth.resetPassword({
token,
newPassword: 'new-secure-password-456',
});
Email Change
const { newEmail, error } = await volcano.auth.requestEmailChange('new@example.com');
// On the confirmation page:const token = newURLSearchParams(window.location.search).get('token');
const { user, error } = await volcano.auth.confirmEmailChange(token);
// Cancel a pending change:await volcano.auth.cancelEmailChange();
// List sessions for the current userconst { sessions, total, error } = await volcano.auth.getSessions({ page: 1, limit: 20 });
// session fields: user_agent, ip_address, last_activity_at, is_current// Revoke a specific sessionawait volcano.auth.deleteSession(sessionId);
// Revoke all OTHER sessions (keep current)await volcano.auth.deleteAllOtherSessions();
Security Best Practices
Never put a service key (sk-...) in anonKey. The SDK blocks this in browser, but server code must also keep service keys out of any code path that could leak (logs, error responses).
Always use HTTPS API URLs in production.
Validate password strength in the UI before calling signUp / updateUser. The SDK rejects weak passwords, but pre-validating gives better UX. The platform enforces a hard floor of 15 characters — a project can raise the minimum via min_password_length but cannot lower it below 15 (the validator uses max(15, configured)). Character-class rules (uppercase/number/special) are off by default and opt-in per project — the floor favors length over complexity. Use ≥15-char passwords in signup forms, tests, and seed data.
Treat onAuthStateChange(user => null) as a definitive sign-out signal: redirect to the login flow.
Common Errors
Message contains
Real example message
Meaning
Action
already exists
user with this email already exists
Email taken on sign up
Prompt sign in
password must
password must be at least 15 characters / password must contain at least one uppercase letter / ...one number / ...one special character (!@#$%^&*)
Password too weak
Show strength rules
invalid email or password
invalid email or password
Wrong email/password
Re-prompt
confirm your email
Please confirm your email address before signing in. (sign-in gate) or email confirmation required - please check your email for confirmation link (signup)
Verification pending
Show resend UI
rate limit
rate limit exceeded, try again later
Rate-limited
Back off and inform user
No active session
No active session
User not logged in
Send to login
Session expired
Session expired
Refresh failed
Force sign in
Verification Checklist
If the prompt didn't specify signup/login page design, the "Default Signup & Login Page UX" was applied, including the default signup-success alert.
Session restore (volcano.initialize()) is wired at app startup.
onAuthStateChange listener has a paired unsubscribe() on teardown.
OAuth methods are only called from browser contexts.
Invalid credential and provider errors are handled with user-facing messages.
No service/secret keys are exposed in browser code.
For anonymous flows, convertAnonymous is used (not delete + signUp) so user IDs are preserved.