Authentication
Passwordless magic link authentication for your customers.
How It Works
StackBE provides passwordless authentication via magic links. Here's the flow:
- Your app calls
POST /auth/magic-linkwith the user's email - StackBE sends an email with a secure, time-limited link
- User clicks the link and is redirected to your callback URL with a token
- Your app verifies the token and receives a session
- Use the session token for authenticated API requests
Send Magic Link
Request a magic link for a customer. If the customer doesn't exist and autoCreateCustomer is enabled, they'll be created automatically.
// Using the SDK
await stackbe.auth.sendMagicLink('user@example.com', {
redirectUrl: 'https://yourapp.com/dashboard', // Optional: where to go after auth
});
// Or via API
// POST /v1/apps/{appId}/auth/magic-link
// Body: { "email": "user@example.com" }The magic link expires after 15 minutes by default (configurable in app settings).
Verify Token
When the user clicks the magic link, they're redirected to your callback URL with a token query parameter. Verify it to get a session:
// In your callback route (e.g., /auth/callback)
const token = searchParams.get('token');
const result = await stackbe.auth.verifyToken(token);
// Returns: { sessionToken, customer, entitlements }
// Store the session token (e.g., in a cookie)
cookies.set('session', result.sessionToken, {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7, // 7 days
});
// Redirect to dashboard
redirect('/dashboard');Using Sessions
Once you have a session token, use it to make authenticated requests on behalf of the customer:
// Get current session info
const session = await stackbe.auth.getSession(sessionToken);
// Returns: { customer, entitlements, organizationId?, orgRole? }
// The session includes:
// - customer: { id, email, name, metadata }
// - entitlements: { planName, features: {...} }
// - organizationId: (if in org context)
// - orgRole: 'owner' | 'admin' | 'member' (if in org context)Session Caching
The SDK can cache sessions to reduce API calls. Configure with sessionCacheTTL:
const stackbe = new StackBE({
apiKey: process.env.STACKBE_API_KEY!,
appId: process.env.STACKBE_APP_ID!,
sessionCacheTTL: 120, // Cache for 2 minutes
});Organization Context
For apps with organizations enabled, customers can belong to multiple orgs. After login, they can switch context:
// List customer's organizations
const orgs = await stackbe.organizations.list(customerId);
// Switch to an organization context
const newSession = await stackbe.auth.switchOrganization(
sessionToken,
organizationId
);
// The new session token includes org context:
// { organizationId: 'org_123', orgRole: 'admin' }When in org context, entitlement checks use the organization's subscription, not the individual customer's.
Callback URLs
When a user clicks the magic link, StackBE redirects them to your callback URL. Configure allowed URL patterns in your dashboard, then pass the callback URL with each request.
Step 1: Configure Allowed URL Patterns
In your StackBE dashboard, configure which callback URLs are allowed:
- Go to app.stackbe.io
- Select your app → Settings → Dev
- Add patterns to "Allowed Callback URLs"
# Example patterns (one per line):
https://app.yoursite.com/*
https://*.vercel.app/*
http://localhost:*/*Localhost URLs (http://localhost:*/*) are always allowed by default. Use * as a wildcard to match any characters.
Step 2: Pass Callback URL with Each Request
Pass the callback URL with every magic link request. This is the recommended approach:
// Determine callback URL based on environment
const callbackUrl = process.env.NODE_ENV === 'production'
? 'https://yourapp.com/auth/callback'
: 'http://localhost:3000/auth/callback';
await stackbe.auth.sendMagicLink('user@example.com', {
redirectUrl: callbackUrl, // Must match an allowed pattern
});Benefits of This Approach
- Single source of truth - callback URL lives in your code
- Preview deployments work - use wildcards like
https://*.vercel.app/* - Local dev just works - localhost is always allowed
- Security via allowlist - only approved URLs can be used
SDK Configuration (Optional)
The SDK also supports devCallbackUrl for automatic localhost detection:
const stackbe = new StackBE({
apiKey: process.env.STACKBE_API_KEY!,
appId: process.env.STACKBE_APP_ID!,
devCallbackUrl: 'http://localhost:3000/auth/callback',
});
// Uses devCallbackUrl when NODE_ENV !== 'production'
await stackbe.auth.sendMagicLink('user@example.com');Note: Explicit redirectUrl always takes priority over SDK defaults.
Custom Verification URL (Branded Emails)
By default, magic link emails contain a link to api.stackbe.io. To show your own domain in email links, configure a Custom Verification URL.
How It Works
- Set your Custom Verification URL in app settings (e.g.,
https://yourapp.com/auth/verify) - Magic link emails now link to your domain:
https://yourapp.com/auth/verify?token=xxx&appId=xxx - Your endpoint redirects to StackBE to complete verification
- StackBE verifies the token and redirects to your callback URL
Implementation (One-Line Redirect)
Create a simple route that forwards to StackBE:
// Next.js App Router: app/auth/verify/route.ts
export async function GET(request: Request) {
const url = new URL(request.url);
const token = url.searchParams.get('token');
const appId = url.searchParams.get('appId');
// Redirect to StackBE for verification
return Response.redirect(
`https://api.stackbe.io/v1/apps/${appId}/auth/verify?token=${token}&redirect=true`
);
}Configuration
- Go to app.stackbe.io → Your App → Settings → Dev
- Set "Custom Verification URL" to your endpoint (e.g.,
https://yourapp.com/auth/verify) - Deploy your redirect endpoint
- Test by requesting a magic link