| name | volcano-auth |
| description | Detailed guidance for authentication flows built with the Volcano SDK |
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.
Initialization
import { VolcanoAuth } from '@volcano.dev/sdk';
const volcano = new VolcanoAuth({
apiUrl: process.env.NEXT_PUBLIC_VOLCANO_API_URL!,
anonKey: process.env.NEXT_PUBLIC_VOLCANO_ANON_KEY!,
});
volcano.database(process.env.NEXT_PUBLIC_VOLCANO_DATABASE_NAME!);
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: '...' },
});
if (error) {
if (error.message.includes('already exists')) ;
else if (error.message.includes('weak password')) ;
else if (error.message.includes('invalid email')) ;
return;
}
Sign In
const { user, session, error } = await volcano.auth.signIn({ email, password });
if (error) {
if (error.message.includes('invalid email or password')) ;
else if (error.message.includes('email not confirmed')) ;
else if (error.message.includes('too many attempts')) ;
return;
}
Sign Out
const { error } = await volcano.auth.signOut();
Session Management
Synchronous current user (cached)
const user = volcano.auth.user();
Fresh user from server
const { user, error } = await volcano.auth.getUser();
Restore session on app load (handles OAuth callback tokens too)
const { user, error } = await volcano.initialize();
Auth state listener
const unsubscribe = volcano.auth.onAuthStateChange((user) => {
if (user) showApp(user); else showLogin();
});
Manual refresh
const { session, error } = await volcano.auth.refreshSession();
OAuth / SSO
Providers
google, github, microsoft, apple.
Begin OAuth (browser only — throws on server)
volcano.auth.signInWithGoogle();
volcano.auth.signInWithGitHub();
volcano.auth.signInWithMicrosoft();
volcano.auth.signInWithApple();
volcano.auth.signInWithOAuth('google');
These redirect to the provider; on return, call volcano.initialize() on the callback page to consume the tokens from the URL.
Link / unlink / list providers
const { data, error } = await volcano.auth.linkOAuthProvider('google');
if (data) window.location.href = data.authorization_url;
await volcano.auth.unlinkOAuthProvider('google');
const { providers, error } = await volcano.auth.getLinkedOAuthProviders();
Call provider APIs through the SDK
const { data, error } = await volcano.auth.callOAuthAPI('github', {
endpoint: '/user/repos',
method: 'GET',
});
Anonymous Users
const { user, session, error } = await volcano.auth.signUpAnonymous({
preferred_theme: 'dark',
});
const { user, error } = await volcano.auth.convertAnonymous({
email: 'alice@example.com',
password: 'secure-password-123',
metadata: { full_name: 'Alice' },
});
Email Verification
const token = new URLSearchParams(window.location.search).get('token');
const { error } = await volcano.auth.confirmEmail(token);
await volcano.auth.resendConfirmation('alice@example.com');
Password Recovery
await volcano.auth.forgotPassword('alice@example.com');
const token = new URLSearchParams(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');
const token = new URLSearchParams(window.location.search).get('token');
const { user, error } = await volcano.auth.confirmEmailChange(token);
await volcano.auth.cancelEmailChange();
Profile Update
const { user, error } = await volcano.auth.updateUser({
password: 'new-password-789',
metadata: {
full_name: 'Alice Johnson',
avatar_url: '...',
notification_preferences: { email: true, push: false },
},
});
Multi-Device Session Management
const { sessions, total, error } = await volcano.auth.getSessions({ page: 1, limit: 20 });
await volcano.auth.deleteSession(sessionId);
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.
- Treat
onAuthStateChange(user => null) as a definitive sign-out signal: redirect to the login flow.
Common Errors
| Message contains | Meaning | Action |
|---|
already exists | Email taken on sign up | Prompt sign in |
weak password | Password too weak | Show strength rules |
invalid email or password | Wrong email/password | Re-prompt |
email not confirmed | Verification pending | Show resend UI |
too many attempts | Rate-limited | Back off and inform user |
No active session | User not logged in | Send to login |
Session expired | Refresh failed | Force sign in |
Verification Checklist
- 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.
Optional Fallback Reference