Clerk logo

Clerk Docs

Ctrl + K
Go to clerk.devGet API keys

Embeddable magic links

Learn how to build custom magic link flows to increase user engagement and reduce drop off in transactional emails, SMSs and anywhere else you can imagine.

Overview

A "magic link" is a link, that when pressed, will automatically authenticate your user, so that they can quickly perform some action on your site with less friction than if they had to sign in manually.

Common use cases include:

  • Welcome emails, when users are added off a waitlist.
  • Promotional emails for users.
  • Recovering abandoned carts.
  • Surveys or questionnaires

Embeddable magic links leverage sign in tokens which can be created from your backend.

Create a sign in token
1
curl --request POST \
2
--url 'https://api.clerk.dev/v1/sign_in_tokens' \
3
-H 'Authorization: Bearer YOUR_BACKEND_API_KEY' \
4
-H 'Content-Type: application/json' \
5
-d '{
6
"user_id": "user_28dVmJleKwFWrefTJN7skmrbtJi",
7
}'

This will return a token, which can then be embedded as a query param in any link, something like:

https://your-site.com/welcome?token=THE_TOKEN

Once you have the link, this can be embedded anywhere, such as an email.

Now that you have a way to process a token, you'll need to setup a page on your frontend to get the token from the query string, call the sign in function, then perform whatever action you originally had in mind.

Signing a user in with a token is very similar to all of our other custom flows.

React pseudo-code

Sign the user in
1
// Grab the sign in token from the query string
2
const queryParams = new URLSearchParams(window.location.search);
3
const signInToken = queryParams.get('token');
4
5
const { signIn, setSession } = useSignIn();
6
7
// Create a sign in with the ticket strategy, and the sign-in-token
8
const res = await signIn.create({
9
strategy: "ticket",
10
ticket: "signInToken",
11
});
12
13
// Set the session as active, and then do whatever you need to!
14
setSession(res.createdSessionId, () => console.log("SignedIn!"));

Complete NextJS example

NextJS complete page
1
import { InferGetServerSidePropsType, GetServerSideProps } from "next";
2
import { useUser, useSignIn } from "@clerk/nextjs";
3
import { useEffect, useState } from "react";
4
5
// Grab the query param server side, and pass through props
6
export const getServerSideProps: GetServerSideProps = async (context) => {
7
return {
8
props: { signInToken: context.query.token ? context.query.token : null },
9
};
10
};
11
12
const AcceptToken = ({
13
signInToken,
14
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {
15
const { signIn, setSession } = useSignIn();
16
const { user } = useUser();
17
const [signInProcessed, setSignInProcessed] = useState<boolean>(false);
18
19
useEffect(() => {
20
if (!signIn || !setSession || !signInToken) {
21
return;
22
}
23
24
const aFunc = async () => {
25
try {
26
// Create a signIn with the token, note that you need to use the "ticket" strategy.
27
const res = await signIn.create({
28
strategy: "ticket",
29
ticket: signInToken as string,
30
});
31
32
setSession(res.createdSessionId, () => {
33
setSignInProcessed(true);
34
});
35
} catch (err) {
36
setSignInProcessed(true);
37
}
38
};
39
40
aFunc();
41
}, [signIn, setSession]);
42
43
if (!signInToken) {
44
return <div>no token provided</div>;
45
}
46
47
if (!signInProcessed) {
48
return <div>loading</div>;
49
}
50
51
if (!user) {
52
return <div>error invalid token</div>;
53
}
54
55
return <div>Signed in as {user.id}</div>;
56
};
57
58
export default AcceptToken;
59

Was this helpful?

Clerk © 2022