JSPM

@vaif/auth

2.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 82
  • Score
    100M100P100Q7263F
  • License MIT

Official authentication SDK for VAIF Studio — session management, OAuth, MFA, magic links, and storage adapters. Ships standalone or bundled into @vaif/client.

Package Exports

  • @vaif/auth
  • @vaif/auth/react

Readme

@vaif/auth

npm version License: MIT TypeScript

Comprehensive authentication SDK for VAIF Studio - session management, OAuth, MFA, magic links, and React hooks.

Installation

npm install @vaif/auth
# or
pnpm add @vaif/auth
# or
yarn add @vaif/auth

Quick Start

import { createAuthClient } from '@vaif/auth';

const auth = createAuthClient({
  url: 'https://api.vaif.studio',
  apiKey: 'your-project-key',
});

// Sign up
const { session, user } = await auth.signUp({
  email: 'user@example.com',
  password: 'secure-password',
  name: 'John Doe',
});

// Sign in
const result = await auth.signInWithPassword({
  email: 'user@example.com',
  password: 'secure-password',
});

// Listen to auth state changes
const { unsubscribe } = auth.onAuthStateChange((event) => {
  console.log('Auth event:', event.event);
  console.log('User:', event.session?.user);
});

// Sign out
await auth.signOut();

Features

  • Email/Password - Sign up, sign in, password reset
  • OAuth - Google, GitHub, Microsoft, Apple, Discord, Slack, Twitter, Facebook, LinkedIn, Spotify, Twitch, Notion, Figma, Zoom
  • Magic Link - Passwordless email authentication
  • OTP - One-time password via SMS, WhatsApp, or email
  • Anonymous Auth - Guest sessions with optional conversion
  • SSO - SAML and OIDC enterprise single sign-on
  • MFA - TOTP, SMS, and email second factors with backup codes
  • Session Management - Auto-refresh, multi-tab sync, session listing/revocation
  • React Integration - Provider, hooks, and SSR support
  • Storage Adapters - localStorage, sessionStorage, cookies, memory, or custom
  • PKCE Flow - Secure OAuth with code challenge

Authentication Methods

Email/Password

// Sign up
const { session, user } = await auth.signUp({
  email: 'user@example.com',
  password: 'secure-password',
  name: 'Jane Doe',
  metadata: { role: 'developer' },
});

// Sign in
const result = await auth.signInWithPassword({
  email: 'user@example.com',
  password: 'secure-password',
  rememberMe: true,
});

// Handle MFA challenge if enabled
if ('mfaRequired' in result) {
  const session = await auth.verifyMFAChallenge(result.mfaToken, '123456');
}

OAuth

// Redirect to OAuth provider
await auth.signInWithOAuth({
  provider: 'google',
  redirectTo: 'https://myapp.com/auth/callback',
  scopes: ['email', 'profile'],
});

// Link additional provider to existing account
await auth.linkIdentity('github', { redirectTo: 'https://myapp.com/settings' });

// Get linked identities
const identities = await auth.getUserIdentities();

// Unlink provider
await auth.unlinkIdentity('github');
await auth.signInWithMagicLink({
  email: 'user@example.com',
  redirectTo: 'https://myapp.com/dashboard',
  shouldCreateUser: true,
});

OTP (One-Time Password)

// Send OTP
await auth.signInWithOTP({
  phone: '+1234567890',
  channel: 'sms', // 'sms' | 'whatsapp' | 'email'
});

// Verify OTP
const { session, user } = await auth.verifyOTP({
  phone: '+1234567890',
  token: '123456',
  type: 'magiclink',
});

Anonymous Auth

const { session, user } = await auth.signInAnonymously({
  metadata: { source: 'landing-page' },
});

SSO (Enterprise)

await auth.signInWithSSO({
  domain: 'acme.com',
  redirectTo: 'https://myapp.com/auth/callback',
});

MFA (Multi-Factor Authentication)

// List enrolled factors
const factors = await auth.listMFAFactors();

// Enroll TOTP
const { qrCode, secret, backupCodes } = await auth.enrollMFA({
  type: 'totp',
  friendlyName: 'My Authenticator',
});

// Verify and activate factor
await auth.verifyMFA({ factorId: factor.id, code: '123456' });

// Regenerate backup codes
const { backupCodes } = await auth.regenerateBackupCodes();

// Unenroll factor
await auth.unenrollMFA(factorId, '123456');

Session Management

// Get current session and user
const session = await auth.getSession();
const user = await auth.getUser();

// Manually set session (SSR)
await auth.setSession(accessToken, refreshToken);

// Refresh session
await auth.refreshSession();

// List all active sessions
const sessions = await auth.listSessions();

// Revoke a specific session
await auth.revokeSession(sessionId);

// Revoke all sessions except current
await auth.revokeOtherSessions();

// Sign out from all devices
await auth.signOutAll();

Password Management

// Request password reset email
await auth.resetPasswordForEmail({
  email: 'user@example.com',
  redirectTo: 'https://myapp.com/reset-password',
});

// Update password (authenticated)
await auth.updatePassword({
  currentPassword: 'old-password',
  newPassword: 'new-password',
});

// Set password with recovery token
await auth.setPassword({
  token: 'recovery-token-from-email',
  password: 'new-password',
});

User Management

// Update user profile
const user = await auth.updateUser({
  name: 'Updated Name',
  avatarUrl: 'https://example.com/avatar.jpg',
  metadata: { theme: 'dark' },
});

// Resend email verification
await auth.resendEmailVerification({
  redirectTo: 'https://myapp.com/verify',
});

// Verify email
await auth.verifyEmail(token);

React Integration

The package includes a complete React integration via the @vaif/auth/react subpath.

AuthProvider

import { AuthProvider, useAuth } from '@vaif/auth/react';

function App() {
  return (
    <AuthProvider config={{ url: 'https://api.vaif.studio', apiKey: 'your-key' }}>
      <YourApp />
    </AuthProvider>
  );
}

// Or pass a pre-configured client
import { createAuthClient } from '@vaif/auth';

const client = createAuthClient({ url: '...', apiKey: '...' });

function App() {
  return (
    <AuthProvider client={client}>
      <YourApp />
    </AuthProvider>
  );
}

useAuth

function LoginPage() {
  const {
    user,
    session,
    isLoading,
    isAuthenticated,
    error,
    signUp,
    signInWithPassword,
    signInWithOAuth,
    signInWithMagicLink,
    signOut,
    refreshSession,
    client, // for advanced usage
  } = useAuth();

  if (isLoading) return <Loading />;
  if (isAuthenticated) return <Redirect to="/dashboard" />;

  return (
    <div>
      <form onSubmit={async (e) => {
        e.preventDefault();
        await signInWithPassword({ email, password });
      }}>
        <input type="email" value={email} onChange={...} />
        <input type="password" value={password} onChange={...} />
        <button type="submit">Sign In</button>
      </form>

      <button onClick={() => signInWithOAuth({ provider: 'google' })}>
        Sign in with Google
      </button>
    </div>
  );
}

Convenience Hooks

import {
  useUser,
  useSession,
  useIsAuthenticated,
  useAuthClient,
  usePassword,
  useMFA,
  useIdentities,
  useSessions,
  useSSO,
} from '@vaif/auth/react';

// Get current user
const user = useUser();

// Get current session
const session = useSession();

// Check auth status
const isAuthenticated = useIsAuthenticated();

// Password management
const { resetPassword, updatePassword, isLoading } = usePassword();

// MFA management
const { factors, enrollTOTP, verifyMFA, unenroll, isLoading } = useMFA();

// OAuth identities
const { identities, linkIdentity, unlinkIdentity } = useIdentities();

// Session management
const { sessions, revokeSession, revokeOtherSessions } = useSessions();

// SSO
const { signInWithSSO, isLoading } = useSSO();

Auth State Events

const { unsubscribe } = auth.onAuthStateChange((event) => {
  switch (event.event) {
    case 'SIGNED_IN':
      console.log('User signed in:', event.session?.user.email);
      break;
    case 'SIGNED_OUT':
      console.log('User signed out');
      break;
    case 'TOKEN_REFRESHED':
      console.log('Token refreshed');
      break;
    case 'USER_UPDATED':
      console.log('User updated:', event.session?.user);
      break;
    case 'PASSWORD_RECOVERY':
      console.log('Password recovery flow completed');
      break;
    case 'MFA_CHALLENGE_VERIFIED':
      console.log('MFA challenge verified');
      break;
    case 'INITIAL_SESSION':
      console.log('Session restored from storage');
      break;
  }
});

// Unsubscribe when done
unsubscribe();

Configuration

import { createAuthClient, cookieStorage } from '@vaif/auth';

const auth = createAuthClient({
  // Required
  url: 'https://api.vaif.studio',

  // Authentication
  apiKey: 'your-project-key',      // Publishable project key
  headers: {},                       // Custom request headers

  // Session persistence
  storage: cookieStorage({           // localStorage (default), sessionStorage, cookieStorage, or custom
    secure: true,
    sameSite: 'lax',
    domain: '.myapp.com',
  }),
  storageKey: 'vaif.auth.',         // Storage key prefix
  persistSession: true,              // Persist session to storage
  autoRefreshToken: true,            // Auto-refresh before expiry

  // OAuth
  detectSessionInUrl: true,          // Auto-detect OAuth callbacks
  flowType: 'pkce',                  // 'implicit' or 'pkce'

  // Debug
  debug: false,                      // Log auth events to console
});

Error Handling

import { AuthError, SessionExpiredError, InvalidCredentialsError } from '@vaif/auth';

try {
  await auth.signInWithPassword({ email, password });
} catch (error) {
  if (error instanceof InvalidCredentialsError) {
    showError('Invalid email or password');
  } else if (error instanceof SessionExpiredError) {
    redirectTo('/login');
  } else if (AuthError.isAuthError(error)) {
    switch (error.code) {
      case 'user_already_exists':
        showError('Account already exists');
        break;
      case 'weak_password':
        showError('Password is too weak');
        break;
      case 'rate_limited':
        showError('Too many attempts, please try later');
        break;
      case 'mfa_required':
        showMFAPrompt();
        break;
      default:
        showError(error.message);
    }
  }
}

Error Codes

Code Description
invalid_credentials Wrong email or password
user_not_found No user with that email
user_already_exists Email already registered
email_not_verified Email verification required
invalid_token Invalid or malformed token
token_expired Access or refresh token expired
session_expired Session no longer valid
mfa_required MFA verification needed
mfa_invalid Invalid MFA code
rate_limited Too many requests
weak_password Password doesn't meet requirements
network_error Network connectivity issue

Storage Adapters

import {
  memoryStorage,       // In-memory (default for Node.js)
  localStorage,        // Browser localStorage (default for browser)
  sessionStorage,      // Browser sessionStorage
  cookieStorage,       // Secure cookies
} from '@vaif/auth';

// Custom adapter
const customStorage = {
  getItem: (key: string) => redis.get(key),
  setItem: (key: string, value: string) => redis.set(key, value),
  removeItem: (key: string) => redis.del(key),
};

License

MIT