Skip to main content
This guide covers implementing authentication flows using the WorkOS User Management API, including password authentication, magic links, MFA, and session management.

Prerequisites

npm install @workos-inc/node
import { WorkOS } from '@workos-inc/node';

const workos = new WorkOS(process.env.WORKOS_API_KEY, {
  clientId: process.env.WORKOS_CLIENT_ID
});

Password Authentication

1

Create a User

Create a user with email and password:
const user = await workos.userManagement.createUser({
  email: '[email protected]',
  password: 'secure-password',
  firstName: 'John',
  lastName: 'Doe',
  emailVerified: false
});

console.log(user.id);           // user_123
console.log(user.email);        // [email protected]
console.log(user.emailVerified); // false
2

Authenticate with Password

Authenticate users with their email and password:
const { user, accessToken, refreshToken } = 
  await workos.userManagement.authenticateWithPassword({
    clientId: process.env.WORKOS_CLIENT_ID,
    email: '[email protected]',
    password: 'secure-password'
  });

console.log('Logged in:', user.email);
console.log('Access token:', accessToken);
3

Handle Session Cookies

Seal session data in encrypted cookies:
const response = await workos.userManagement.authenticateWithPassword({
  clientId: process.env.WORKOS_CLIENT_ID,
  email: '[email protected]',
  password: 'secure-password',
  session: {
    sealSession: true,
    cookiePassword: process.env.COOKIE_PASSWORD // 32+ character secret
  }
});

// Set the encrypted session cookie
res.cookie('wos-session', response.sealedSession, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});
4

Verify Session Cookies

Authenticate requests using session cookies:
const session = await workos.userManagement.authenticateWithSessionCookie({
  sessionData: req.cookies['wos-session'],
  cookiePassword: process.env.COOKIE_PASSWORD
});

if (session.authenticated) {
  console.log('User:', session.user.email);
  console.log('Session ID:', session.sessionId);
  console.log('Organization:', session.organizationId);
  console.log('Permissions:', session.permissions);
} else {
  console.log('Invalid session:', session.reason);
}
1

Create a Magic Auth Link

Generate a magic authentication link:
const magicAuth = await workos.userManagement.createMagicAuth({
  email: '[email protected]',
  invitationToken: 'optional_invitation_token'
});

console.log(magicAuth.id);    // magic_auth_123
console.log(magicAuth.code);  // Secret code for email
console.log(magicAuth.email); // [email protected]

// Send magicAuth.code via email to the user
2

Authenticate with Magic Auth Code

Verify the code when user clicks the link:
const { user, accessToken } = 
  await workos.userManagement.authenticateWithMagicAuth({
    clientId: process.env.WORKOS_CLIENT_ID,
    code: '123456',
    email: '[email protected]'
  });

console.log('User authenticated:', user.email);

OAuth 2.0 Flow

1

Generate Authorization URL

Redirect users to the WorkOS authentication page:
const authorizationUrl = workos.userManagement.getAuthorizationUrl({
  provider: 'authkit',
  clientId: process.env.WORKOS_CLIENT_ID,
  redirectUri: 'http://localhost:3000/callback',
  state: 'random-state'
});

res.redirect(authorizationUrl);
For public clients, use automatic PKCE:
const { url, state, codeVerifier } = 
  await workos.userManagement.getAuthorizationUrlWithPKCE({
    provider: 'authkit',
    clientId: process.env.WORKOS_CLIENT_ID,
    redirectUri: 'myapp://callback'
  });

// Store state and codeVerifier securely
2

Exchange Authorization Code

Exchange the authorization code for tokens:
const { user, accessToken, refreshToken } = 
  await workos.userManagement.authenticateWithCode({
    clientId: process.env.WORKOS_CLIENT_ID,
    code: req.query.code as string
  });

// For public clients with PKCE:
const result = await workos.userManagement.authenticateWithCode({
  clientId: process.env.WORKOS_CLIENT_ID,
  code: req.query.code as string,
  codeVerifier: storedCodeVerifier
});
3

Refresh Access Tokens

Use refresh tokens to get new access tokens:
const { accessToken, refreshToken } = 
  await workos.userManagement.authenticateWithRefreshToken({
    clientId: process.env.WORKOS_CLIENT_ID,
    refreshToken: storedRefreshToken
  });

console.log('New access token:', accessToken);

Multi-Factor Authentication

1

Enroll TOTP Factor

Enroll users in TOTP-based MFA:
const { authenticationFactor, authenticationChallenge } = 
  await workos.userManagement.enrollAuthFactor({
    userId: 'user_123',
    type: 'totp'
  });

// Display authenticationFactor.totp.qrCode to user
console.log('QR Code:', authenticationFactor.totp?.qrCode);
console.log('Secret:', authenticationFactor.totp?.secret);
2

Verify TOTP Code

After initial password authentication, verify the TOTP code:
// First authenticate with password
const passwordAuth = await workos.userManagement.authenticateWithPassword({
  clientId: process.env.WORKOS_CLIENT_ID,
  email: '[email protected]',
  password: 'secure-password'
});

// User is prompted for MFA
if (passwordAuth.authenticationMethod === 'Password') {
  // Verify TOTP code
  const { user, accessToken } = 
    await workos.userManagement.authenticateWithTotp({
      clientId: process.env.WORKOS_CLIENT_ID,
      code: '123456',
      authenticationChallengeId: passwordAuth.authenticationChallengeId,
      pendingAuthenticationToken: passwordAuth.pendingAuthenticationToken
    });

  console.log('MFA verified:', user.email);
}
3

List Authentication Factors

View all enrolled MFA factors for a user:
const factors = await workos.userManagement.listAuthFactors({
  userId: 'user_123'
});

for await (const factor of factors.autoPagination()) {
  console.log(factor.id, factor.type, factor.totp);
}

Email Verification

1

Send Verification Email

Send a verification email to a user:
const { user } = await workos.userManagement.sendVerificationEmail({
  userId: 'user_123'
});

console.log('Verification sent to:', user.email);
2

Verify Email with Code

Complete email verification:
const { user } = await workos.userManagement.verifyEmail({
  userId: 'user_123',
  code: '123456'
});

console.log('Email verified:', user.emailVerified);
3

Authenticate with Email Verification

Complete authentication after email verification:
const { user, accessToken } = 
  await workos.userManagement.authenticateWithEmailVerification({
    clientId: process.env.WORKOS_CLIENT_ID,
    code: '123456',
    pendingAuthenticationToken: 'pending_token'
  });

Password Reset

1

Create Password Reset

Generate a password reset token:
const passwordReset = await workos.userManagement.createPasswordReset({
  email: '[email protected]'
});

console.log('Reset token:', passwordReset.passwordResetToken);
console.log('Reset URL:', passwordReset.passwordResetUrl);

// Send passwordReset.passwordResetUrl via email
2

Complete Password Reset

Reset the password with the token:
const { user } = await workos.userManagement.resetPassword({
  token: 'password_reset_token',
  newPassword: 'new-secure-password'
});

console.log('Password reset for:', user.email);

Managing Users

Get User

const user = await workos.userManagement.getUser('user_123');

console.log(user.email);
console.log(user.firstName);
console.log(user.emailVerified);
console.log(user.createdAt);

List Users

const users = await workos.userManagement.listUsers({
  email: '[email protected]',
  organizationId: 'org_123',
  limit: 10
});

for await (const user of users.autoPagination()) {
  console.log(user.email);
}

Update User

const user = await workos.userManagement.updateUser({
  userId: 'user_123',
  firstName: 'Jane',
  lastName: 'Smith',
  emailVerified: true
});

Delete User

await workos.userManagement.deleteUser('user_123');

Session Management

List User Sessions

const sessions = await workos.userManagement.listSessions('user_123');

for await (const session of sessions.autoPagination()) {
  console.log(session.id, session.ipAddress);
}

Revoke Session

await workos.userManagement.revokeSession({
  sessionId: 'session_123'
});

Get Logout URL

const logoutUrl = workos.userManagement.getLogoutUrl({
  sessionId: 'session_123',
  returnTo: 'https://yourapp.com'
});

res.redirect(logoutUrl);

Complete Authentication Example

import { WorkOS } from '@workos-inc/node';
import express from 'express';
import cookieParser from 'cookie-parser';

const workos = new WorkOS(process.env.WORKOS_API_KEY, {
  clientId: process.env.WORKOS_CLIENT_ID
});

const app = express();
app.use(express.json());
app.use(cookieParser());

// Login endpoint
app.post('/login', async (req, res) => {
  try {
    const { user, sealedSession } = 
      await workos.userManagement.authenticateWithPassword({
        clientId: process.env.WORKOS_CLIENT_ID,
        email: req.body.email,
        password: req.body.password,
        session: {
          sealSession: true,
          cookiePassword: process.env.COOKIE_PASSWORD
        }
      });

    res.cookie('wos-session', sealedSession, {
      httpOnly: true,
      secure: true,
      sameSite: 'lax'
    });

    res.json({ user });
  } catch (error) {
    res.status(401).json({ error: 'Authentication failed' });
  }
});

// Protected route
app.get('/profile', async (req, res) => {
  const session = await workos.userManagement.authenticateWithSessionCookie({
    sessionData: req.cookies['wos-session'],
    cookiePassword: process.env.COOKIE_PASSWORD
  });

  if (!session.authenticated) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  res.json({ user: session.user });
});

// Logout endpoint
app.post('/logout', async (req, res) => {
  const session = await workos.userManagement.getSessionFromCookie({
    sessionData: req.cookies['wos-session'],
    cookiePassword: process.env.COOKIE_PASSWORD
  });

  if (session) {
    await workos.userManagement.revokeSession({
      sessionId: session.sessionId
    });
  }

  res.clearCookie('wos-session');
  res.json({ success: true });
});

app.listen(3000);

Build docs developers (and LLMs) love