The fastest way to securely enable authentication – passwordless sign-in via email in a couple lines of code.
Managing password authentication entails significant overhead for engineering teams and opens up many risks for breaches. Magic Link from WorkOS gives you the ability to build a secure passwordless authentication flow utilizing email. Send users a one-time-use link and let them sign in with a single click.
Magic Link sets you up to handle Single Sign-On via the WorkOS SSO API. The redirect URI / profile retrieval process is identical between Magic Link and SSO.
Magic Link is not a session management solution – instead it is an authentication solution. You as the developer have the ability to manage user sessions as you see fit. This means you determine how long a session is valid for, as well as how to store and invalidate a session.
Magic Links are single use, meaning that they will immediately expire after they are first clicked. If end users have security checks included with their email provider that test all embedded URLs, it can cause the Magic Links to expire before they reach the user’s inbox. To work around this, we recommend that end users add these Magic Link emails to an allowlist in order to bypass these security checks.
In this guide, we’ll take you from learning about passwordless authentication all the way through to building production-ready passwordless authentication flows with the WorkOS Magic Link API.
This guide will show you how to:
WorkOS offers native SDKs in several popular programming languages. Choose a language below to see instructions in your application’s language.
Don't see an SDK you need? Contact us to request an SDK!
To make calls to WorkOS, provide the API key and, in some cases, the client ID. Store these values as managed secrets, such as WORKOS_API_KEY
and WORKOS_CLIENT_ID
, and pass them to the SDKs either as environment variables or directly in your app’s configuration based on your preferences.
WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789'
Let’s first add the redirect endpoint which will handle the callback from WorkOS after a user has authenticated via a magic link. This endpoint should exchange the authorization code (valid for 10 minutes) returned by WorkOS with the authenticated user’s Profile.
The redirect URI must use HTTPS.
import type { NextApiRequest, NextApiResponse } from 'next'; import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); const clientId = process.env.WORKOS_CLIENT_ID; export default async (req: NextApiRequest, res: NextApiResponse) => { const { code } = req.query; const { profile } = await workos.sso.getProfileAndToken({ code, clientId, }); // The user's organization ID const organization = 'org_123'; // Validate that this profile belongs to the organization used for authentication if (profile.organizationId !== organization) { return res.status(401).send({ message: 'Unauthorized', }); } // Use the information in `profile` for further business logic. res.redirect('/'); };
const express = require('express'); const { WorkOS } = require('@workos-inc/node'); const app = express(); const workos = new WorkOS(process.env.WORKOS_API_KEY); const clientId = process.env.WORKOS_CLIENT_ID; app.get('/callback', async (req, res) => { const { code } = req.query; const { profile } = await workos.sso.getProfileAndToken({ code, clientId, }); // The user's organization ID const organization = 'org_123'; // Validate that this profile belongs to the organization used for authentication if (profile.organizationId !== organization) { return res.status(401).send({ message: 'Unauthorized', }); } // Use the information in `profile` for further business logic. res.redirect('/'); });
Create a Passwordless Session to generate an authentication link for a user. An authentication link is valid for 15 minutes and can be sent via the WorkOS API or using your own email service.
You can use the optional state
parameter to encode arbitrary information to help restore application state between redirects.
You can use the optional redirect_uri
parameter to override the default Redirect URI set in the dashboard.
A Magic Link Connection will be automatically created if there isn’t already one for the domain specified when creating a new Passwordless Session.
Use the WorkOS API to send the authentication link to the user. The email sent will be WorkOS branded.
import type { NextApiRequest, NextApiResponse } from 'next'; import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); export default async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === 'POST') { // Email of the user to authenticate const email = 'email@example.com'; const session = await workos.passwordless.createSession({ email, type: 'MagicLink', }); // Send an email to the user via WorkOS with the link to authenticate await workos.passwordless.sendSession(session.id); // Finally, redirect to a "Check your email" page res.redirect(307, '/check-email'); } };
const express = require('express'); const { WorkOS } = require('@workos-inc/node'); const app = express(); const workos = new WorkOS(process.env.WORKOS_API_KEY); app.post('/passwordless-auth', async (req, res) => { // Email of the user to authenticate const email = 'email@example.com'; const session = await workos.passwordless.createSession({ email, type: 'MagicLink', }); // Send an email to the user via WorkOS with the link to authenticate await workos.passwordless.sendSession(session.id); // Finally, redirect to a "Check your email" page });
Use your own email service and custom branded email template to send the authentication link to the user.
import type { NextApiRequest, NextApiResponse } from 'next'; import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); export default async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === 'POST') { // Email of the user to authenticate const email = 'email@example.com'; const session = await workos.passwordless.createSession({ email, type: 'MagicLink', }); // Send a custom email using your own service emailService.send({ email, message: session.link, }); // Finally, redirect to a "Check your email" page res.redirect(307, '/check-email'); } };
const express = require('express'); const { WorkOS } = require('@workos-inc/node'); const app = express(); const workos = new WorkOS(process.env.WORKOS_API_KEY); app.post('/passwordless-auth', async (req, res) => { // Email of the user to authenticate const email = 'email@example.com'; const session = await workos.passwordless.createSession({ email, type: 'MagicLink', }); // Send a custom email using your own service emailService.send({ email, message: session.link, }); // Finally, redirect to a "Check your email" page });
You should set a redirect URI (i.e. the callback endpoint from Add a callback endpoint) via the Configuration page in the WorkOS Dashboard – be sure not to include wildcard subdomains or query parameters.