workos-magic-link

Step 1: Fetch Documentation (BLOCKING)

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "workos-magic-link" with this command: npx skills add workos/skills/workos-skills-workos-magic-link

WorkOS Magic Link

Step 1: Fetch Documentation (BLOCKING)

STOP. Do not proceed until complete.

WebFetch these URLs in order:

These docs are the source of truth. If this skill conflicts with the documentation, follow the docs.

CRITICAL DEPRECATION NOTICE: Magic Link is deprecated by WorkOS due to email security software pre-visiting links and invalidating them. The docs recommend Magic Auth instead. Confirm with stakeholders before implementing Magic Link for new projects.

Step 2: Pre-Flight Validation

WorkOS Account Setup

  • Confirm WorkOS account exists at dashboard.workos.com

  • Navigate to Production environment → Settings → API Keys

  • Verify API key starts with sk_

  • Verify Client ID starts with client_

Environment Variables

Check .env or equivalent for:

  • WORKOS_API_KEY

  • starts with sk_ (production or test)

  • WORKOS_CLIENT_ID

  • starts with client_

Warning: Using test environment keys in production will fail. Verify environment matches deployment target.

Redirect URI Configuration

  • Check WorkOS Dashboard → Configuration → Redirect URIs

  • Confirm callback URL matches your app's domain

  • Format: https://yourdomain.com/auth/callback (HTTPS required for production)

Step 3: SDK Installation (Decision Tree)

Detect project language and install appropriate SDK:

Language/Framework? | +-- Node.js/Express --> npm install @workos-inc/node | +-- Python/Flask/Django --> pip install workos | +-- Ruby/Rails --> gem install workos | +-- Go --> go get github.com/workos/workos-go/v4 | +-- Java --> Maven/Gradle (see example apps URL)

Verify: SDK package exists in dependencies before continuing.

Check example apps documentation (from Step 1) for language-specific setup if not listed above.

Step 4: Initialize SDK

Configure SDK with API credentials. Pattern varies by language:

Node.js:

const { WorkOS } = require('@workos-inc/node');

const workos = new WorkOS(process.env.WORKOS_API_KEY); const clientId = process.env.WORKOS_CLIENT_ID;

Python:

import workos

workos.api_key = os.getenv('WORKOS_API_KEY') workos.client_id = os.getenv('WORKOS_CLIENT_ID')

Critical: Never hardcode credentials. Always use environment variables or secret management.

Verify SDK initialization:

Check SDK import doesn't throw

node -e "require('@workos-inc/node'); console.log('SDK loaded')"

Step 5: Create Callback Endpoint

Add a route to handle the OAuth callback from WorkOS. This endpoint:

  • Receives an authorization code parameter (valid 10 minutes)

  • Exchanges code for user Profile

  • Creates application session

  • Redirects to authenticated page

Route location (by framework):

Framework --> Route path Express/Node.js --> app.get('/auth/callback', ...) Flask/Django --> @app.route('/auth/callback') Rails --> get '/auth/callback'

Implementation pattern:

// Node.js/Express example - see docs for other languages app.get('/auth/callback', async (req, res) => { const { code } = req.query;

try { // Exchange code for user profile const profile = await workos.userManagement.authenticateWithCode({ code, clientId, });

// Create your application session
req.session.userId = profile.user.id;
req.session.email = profile.user.email;

// Redirect to app
res.redirect('/dashboard');

} catch (error) { console.error('Auth error:', error); res.redirect('/login?error=auth_failed'); } });

CRITICAL: The code expires after 10 minutes. Handle expiration errors gracefully.

Check the fetched documentation for exact SDK method names — they may vary by language and SDK version.

Step 6: Create Passwordless Session Endpoint

Add an endpoint that generates the Magic Link when user submits their email.

Key parameters:

  • email

  • User's email address (required)

  • redirect_uri

  • Override default callback URL (optional)

  • state

  • Arbitrary data to preserve between redirects (optional)

Implementation pattern:

app.post('/auth/magic-link', async (req, res) => { const { email } = req.body;

try { const session = await workos.passwordless.createSession({ email, type: 'MagicLink', redirectUri: 'https://yourdomain.com/auth/callback', state: JSON.stringify({ returnTo: req.body.returnTo }), });

// Decision: WorkOS email or custom email?
if (useWorkOSEmail) {
  // WorkOS sends branded email automatically
  await workos.passwordless.sendSession(session.id);
} else {
  // Send via your email service
  await yourEmailService.send({
    to: email,
    subject: 'Sign in to YourApp',
    html: `<a href="${session.link}">Click to sign in</a>`,
  });
}

res.json({ success: true });

} catch (error) { res.status(400).json({ error: error.message }); } });

Email delivery decision tree:

Email provider? | +-- Use WorkOS email --> Call sendSession(sessionId) | (WorkOS branded, no customization) | +-- Use custom email --> Send session.link via your service (Full template control, requires email infra)

CRITICAL - Magic Link expiration:

  • Links expire after 15 minutes

  • Links are single-use only

  • Email security software may pre-visit links and invalidate them before user clicks

  • If using corporate email (Gmail, Outlook), advise users to allowlist sender

Check documentation for exact SDK method names (createSession , sendSession ).

Step 7: Domain Connection Auto-Creation

Important: WorkOS automatically creates a Magic Link Connection when you create a Passwordless Session for a new email domain.

Verify in Dashboard:

  1. Go to WorkOS Dashboard → Connections
  2. Find "Magic Link" connection type
  3. Confirm domain appears after first session creation

No manual connection setup required. If domain doesn't appear, check API key permissions.

Step 8: Session Management (CRITICAL)

WorkOS does NOT manage sessions. You must implement:

  • Session creation - After code exchange in callback

  • Session storage - Cookie, JWT, database session, etc.

  • Session validation - Check on protected routes

  • Session expiration - Define timeout policy

  • Logout - Clear session data

Example session middleware:

// Protect routes requiring authentication function requireAuth(req, res, next) { if (!req.session.userId) { return res.redirect('/login'); } next(); }

app.get('/dashboard', requireAuth, (req, res) => { res.render('dashboard', { email: req.session.email }); });

Session duration: You decide. Common patterns:

  • Short (30 min - 1 hour) for high-security apps

  • Long (1-7 days) for consumer apps

  • Remember me checkbox for user choice

Step 9: Production Checklist

Before deploying to production, verify ALL items:

Dashboard Configuration:

  • Production environment unlocked (billing info added)

  • Production Redirect URI configured with HTTPS

  • Production API key secured (not committed to repo)

IP Allowlist (if required):

Code Verification:

  • Callback endpoint handles code exchange

  • Session creation works after authentication

  • Protected routes validate session

  • Logout clears session data

  • Error messages don't expose sensitive data

Email Deliverability:

  • Test email delivery in production domain

  • Configure SPF/DKIM if using custom email

  • Add sender to corporate allowlist (if applicable)

Verification Checklist (ALL MUST PASS)

Run these commands to verify integration:

1. Check SDK installed

npm list @workos-inc/node || pip list | grep workos || gem list | grep workos

2. Check environment variables set

env | grep WORKOS_API_KEY || echo "FAIL: API key not set" env | grep WORKOS_CLIENT_ID || echo "FAIL: Client ID not set"

3. Check callback route exists

grep -r "auth/callback" . --include=".js" --include=".py" --include="*.rb" || echo "FAIL: Callback route not found"

4. Check session management exists

grep -r "session" . --include=".js" --include=".py" --include="*.rb" | grep -v node_modules || echo "FAIL: No session management found"

5. Test endpoint responds (after server start)

curl -X POST http://localhost:3000/auth/magic-link
-H "Content-Type: application/json"
-d '{"email":"test@example.com"}' || echo "FAIL: Magic Link endpoint error"

6. Application builds/starts

npm run build || python app.py || rails server

If any check fails: Review corresponding step before proceeding.

Error Recovery

"Invalid authorization code" during callback

Root cause: Code expired (10 min limit) or already used.

Fix:

  • Check callback executes within 10 minutes of link click

  • Ensure callback doesn't retry/double-submit code

  • Add error handling to redirect user to re-authenticate: catch (error) { if (error.code === 'invalid_grant') { return res.redirect('/login?error=expired'); } }

"Magic Link already used" or link doesn't work

Root cause: Email security software pre-visited link.

Fix:

  • Confirm with user if they use corporate email (Gmail, Outlook, etc.)

  • Advise user to allowlist sender email

  • Consider switching to Magic Auth (not Magic Link) per WorkOS recommendation

  • Check email client settings for link preview/pre-fetch features

Reference: https://workos.com/docs/magic-link/index (deprecation notice section)

"Redirect URI mismatch"

Root cause: Callback URL doesn't match Dashboard configuration.

Fix:

  • Check WorkOS Dashboard → Configuration → Redirect URIs

  • Ensure exact match including protocol (https://) and path

  • If using redirect_uri parameter in createSession, verify it's pre-registered

  • Production must use HTTPS, not HTTP

"Invalid API key"

Root cause: Wrong environment key or key doesn't have permissions.

Fix:

  • Verify key starts with sk_test_ (test) or sk_live_ (production)

  • Check environment matches: test keys don't work in production

  • Regenerate key in Dashboard if compromised

SDK import errors

Root cause: Package not installed or wrong import path.

Fix by language:

Node.js

npm install @workos-inc/node

Check: const { WorkOS } = require('@workos-inc/node')

Python

pip install workos

Check: import workos

Ruby

gem install workos

Check: require 'workos'

Session not persisting after login

Root cause: Session middleware not configured or cookies not working.

Fix:

  • Verify session middleware initialized (express-session, Flask sessions, etc.)

  • Check cookie settings (httpOnly, secure, sameSite)

  • Ensure HTTPS in production (secure cookies require it)

  • Verify session secret is set

Email not delivered

Root cause: Email provider blocking or SPF/DKIM not configured.

Fix:

  • Check spam folder

  • If using WorkOS email: Check Dashboard logs for delivery status

  • If using custom email: Verify email service credentials

  • Configure SPF/DKIM records for custom domain

  • Test with personal email (Gmail) first to isolate corporate email issues

State Parameter Usage

The optional state parameter preserves application context across the auth flow:

Use cases:

  • Return user to original page after login

  • Pass through A/B test variant

  • Preserve shopping cart state

  • Track referral source

Pattern:

// Encode state when creating session const state = JSON.stringify({ returnTo: '/checkout', variant: 'experiment_a', });

await workos.passwordless.createSession({ email, type: 'MagicLink', state, });

// Decode state in callback const { state } = req.query; const { returnTo, variant } = JSON.parse(state); res.redirect(returnTo || '/dashboard');

Security note: Don't put sensitive data in state — it's visible in URL. Use it only for non-sensitive routing/tracking.

Related Skills

  • workos-authkit-nextjs: Full-featured auth with session management built-in

  • workos-magic-auth: Recommended replacement for Magic Link (code-based instead of link-based)

  • workos-sso: Enterprise SSO using same redirect flow as Magic Link

  • workos-mfa: Add second factor to passwordless flows

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

workos

No summary provided by upstream source.

Repository SourceNeeds Review
150-workos
General

workos-authkit-nextjs

No summary provided by upstream source.

Repository SourceNeeds Review
General

workos-authkit-base

No summary provided by upstream source.

Repository SourceNeeds Review
General

workos-authkit-react

No summary provided by upstream source.

Repository SourceNeeds Review