Clerk logo

Clerk Docs

Ctrl + K
Go to clerk.devGet API keys

Remix Authentication

Easily add secure, edge- and SSR-friendly authentication to Remix with Clerk.

Overview

Remix is famous for its speed - both for developers, who are no longer troubled by useEffect for data loading, and for end-users, who reap the speed benefits of server-side rendering and edge compatibility by default. Clerk is also famous for its speed - as the first vendor to champion sub-millisecond, JWT-based authentication for server-side rendered applications without compromising on security. This shared focus makes Clerk an ideal solution for Remix authentication. Clerk provides an NPM library tailored specifically to Remix authentication, with helpers for React pages and Remix loaders.

πŸ‘‰Β Live demo

πŸ‘©β€πŸ’» Looking for a quicker start? Check out the Clerk + Remix starter repo

Installation

Before you start

Before you start, you need to set up your application in your Clerk Dashboard. For more information, check out our Set up your application guide.

Create a Remix application

Start by creating a new Remix application with the npx CLI:

npx create-remix@latest

Choose a directory to create the app and follow these prompts:

  • For app type, select "Just the basics"
  • For deployment target, select "Remix App Server"

Need more help? The Remix documentation goes into more detail about creating applications.

Install Clerk's SDK

Once you have a Remix application ready, you need to install Clerk's Remix SDK. This gives you access to our prebuilt components and hooks for React, as well as our helpers for Remix loaders.

1
# Navigate to your application's root directory
2
cd yourapp
3
4
# Install the clerk/remix package
5
npm install @clerk/remix

Set environment variables

There are 3 important environment variables that you need to know about in Clerk. The Frontend API key, Backend API key, JWT verification key.

You can find them on the API Keys page of your instance.

Frontend API key: This connects your frontend with your instance and is mandatory. This is a "public key", and does not need to be kept secret.

Backend API key: This is used to make admin requests to Clerk's Backend API. This is a "secret key", and MUST BE KEPT SECRET. It has access to modify anything about any of your users. You may not need this in your application.

JWT verification key: This is a public key that is used to validate JWTs, so that you know they are secure. This does not need to be kept secret and you may not need this in your application.

To add environment variables to a Remix application, create a file named .env in the root directory of your project and add your keys there. This is a good time to set all of them so you don't need to worry about them further in the guide.

.env
1
# Replace [frontend-api-key] with your Frontend API Key
2
CLERK_FRONTEND_API=[frontend-api-key]
3
# Replace [backend-api-key] with your Backend API Key
4
CLERK_API_KEY=[backend-api-key]
5
# Replace [jwt-verification-key] with your JWT Verification key
6
CLERK_JWT_KEY=[jwt-verification-key]

Initialize Clerk in app/root.tsx

In Remix, app/root.tsx wraps your entire application in both server and browser contexts. Clerk requires three modifications to this file so we can share the authentication state with your Remix routes.

Set `rootAuthLoader`

First, we must define a root loader.

app/root.tsx
1
// Add imports
2
import type { LoaderFunction } from "@remix-run/node";
3
import { rootAuthLoader } from "@clerk/remix/ssr.server";
4
5
// Define and export your loader
6
export const loader: LoaderFunction = (args) => rootAuthLoader(args);
7

If you'd like to load additional data, you can pass your own loader directly to rootAuthLoader.

app/root.tsx
1
// Add imports
2
import type { LoaderFunction } from "@remix-run/node";
3
import { rootAuthLoader } from "@clerk/remix/ssr.server";
4
5
// Define and export your loader
6
export const loader: LoaderFunction = args => {
7
return rootAuthLoader(args, ({ request }) => {
8
const { sessionId, userId, getToken } = request.auth;
9
// fetch data
10
return { yourData: 'here' };
11
});
12
};

Wrap your App with ClerkApp

Clerk provides a ClerkApp wrapper to provide the authentication state to your React tree. This helper works with Remix SSR out-of-the-box and follows the "higher-order component" paradigm.

First, update App so it is not exported as the default module. Then, wrap App with ClerkApp:

app/root.tsx
1
// add import
2
import { ClerkApp } from "@clerk/remix";
3
4
5
// Remove "export default" from in front of `function App() {`
6
function App() {
7
...
8
}
9
10
// Followed by exporting the "wrapped" App
11
export default ClerkApp(App);

Set ClerkCatchBoundary

Clerk uses Remix's catch boundary in root.tsx to refresh expired authentication tokens.

app/root.tsx
1
// add import
2
import { ClerkCatchBoundary } from "@clerk/remix";
3
4
// define boundary
5
export const CatchBoundary = ClerkCatchBoundary();

You can also add your own boundary, simply by passing it as an argument.

app/root.tsx
1
// add import
2
import { ClerkCatchBoundary } from "@clerk/remix";
3
4
// define boundary
5
export const CatchBoundary = ClerkCatchBoundary(YourBoundary);

That's all!

To run your app, start the development server and navigate to http://localhost:3000

1
npm run dev

Clerk is installed, but you still have to configure your application to actually use authentication. Read on to learn how to protect pages, API routes, and more.

Access authentication data

Once installation is complete, Clerk can seamlessly authenticates users across all three Remix contexts:

  1. React pages
  2. Loaders
  3. Actions

Each context has access to Clerk's auth singleton, which contains the data necessary for authentication and data loading:

  • userId: The ID of the active user, or null when signed out. In data-loaders, this is often the only piece of information needed to securely retrieve the data associated with a request.
  • sessionId: The ID of the active session, or null when signed out. This is primarily used in audit logs to enable device-level granularity instead of user-level.
  • getToken({ template?: string; }): Retrieves a signed JWT that is structured according to the corresponding JWT template in your dashboard. If no template parameter is provided, the default Clerk session JWT is returned.

React

In React, the auth singleton is available via the useAuth hook:

1
import { useAuth } from "@clerk/remix";
2
3
const { userId, sessionId, getToken } = useAuth();

Loaders and actions

In loaders and actions, the auth singleton is available via the getAuth helper.

1
import { getAuth } from "@clerk/remix/ssr.server";
2
3
export const loader: LoaderFunction = async ({ request }) => {
4
const { userId, sessionId, getToken } = await getAuth(request);
5
// fetch data
6
return { yourData: 'here' };
7
}

Protecting routes

To protect a route from signed out users, simply add a redirect to your loader if no userId is found in the auth singleton:

1
export const loader: LoaderFunction = async ({ request }) => {
2
const { userId, sessionId } = await getAuth(request);
3
if(!userId){
4
return redirect("https://accounts.foo.bar.lcl.dev/sign-in");
5
}
6
// Your loader here
7
}

Enabling full server side rendering

To make auth as fast as possible, Clerk uses short-lived stateless JWT tokens by default, requiring no network requests.

If desired, Clerk’s complete User objects can also be retrieved during SSR. Since these objects require network requests to retrieve, so you need to explicitly enable server-side user fetching by passing a flag to the root loader:

1
import { rootAuthLoader } from "@clerk/remix/ssr.server";
2
3
export const loader: LoaderFunction = (args) => {
4
return rootAuthLoader(args, { loadUser: true });
5
};
6
7
// or, if you also need a custom loader handler:
8
export const loader: LoaderFunction = (args) => {
9
return rootAuthLoader(
10
args,
11
({ request }) => {
12
const { userId } = request.auth;
13
// fetch data
14
return { yourData: 'here' };
15
},
16
{ loadUser: true }
17
);
18
};
19

This makes the entire User object available to your components during SSR, allowing the whole app to be rendered on the server side.

Using Clerk Hosted Pages

If you're looking for the fastest way to implement a full-stack authentication into your site, you can leverage Clerk Hosted Pages for your sign up, sign in, and user profile pages.

You can easily define how you want your users to sign in and sign up in the User & Authentication settings page.

By default, the URLs for your hosted pages will match the following pattern:

https://accounts.[your-domain].com/sign-in
https://accounts.[your-domain].com/sign-up
https://accounts.[your-domain].com/user

For development instances, Clerk will issue you a domain on "lcl.dev". In production, you'll need to supply your own domain. See Production setup or more information.

Clerk provides SDKs to make navigating to these pages easy.

1
import {
2
RedirectToSignIn,
3
RedirectToSignUp
4
} from "@clerk/remix";
5
6
// Rendering the RedirectToSignIn component will
7
// cause the browser to navigate to the Sign in
8
// URL and show the Sign In Clerk Hosted Page.
9
function App() {
10
return <RedirectToSignIn />;
11
}
12
13
// Rendering the RedirectToSignUp component will
14
// cause the browser to navigate to the Sign up URL
15
// and show the Sign up Clerk Hosted Page.
16
function App() {
17
return <RedirectToSignUp />;
18
}
1
// redirectToSignIn will cause the browser to
2
// visit the Clerk Hosted Pages Sign in URL.
3
window.Clerk.redirectToSignIn();
4
5
// redirectToSignUp will cause the browser to
6
// visit the Clerk Hosted Pages Sign up URL.
7
window.Clerk.redirectToSignUp();

Using Clerk Components

If you want more control over the look and feel of your sign in and sign up experience but don't want to completely build one from scratch, you can use the pre-built Clerk Components.

Clerk provides <SignIn />, <SignUp /> and <UserProfile /> components that render entire flows. Using these, Clerk will take care of everything from verifying the user's email address to letting your user add 2FA. These in conjunction with Remix's router gives you a complete solution that's surprisingly easy to implement and is completely customizable via CSS.

Sign up Pages

app/routes/sign-up/$.tsx
1
import { SignUp } from "@clerk/remix";
2
3
export default function SignUpPage() {
4
return (
5
<div style={{ border: "2px solid blue", padding: "2rem" }}>
6
<h1>Sign Up route</h1>
7
<SignUp routing={"path"} path={"/sign-up"} />
8
</div>
9
);
10
}

Sign in Pages

app/routes/sign-in/$.tsx
1
import { SignIn } from "@clerk/remix";
2
3
export default function SignInPage() {
4
return (
5
<div style={{ border: "2px solid blue", padding: "2rem" }}>
6
<h1>Sign In route</h1>
7
<SignIn routing={"path"} path={"/sign-in"} />
8
</div>
9
);
10
}

Once these files have been added, re-run `npm run dev` and navigate to localhost:3000/sign-in

In order to make the links on the modal work, you'll need to set these in the Clerk Dashboard on the Paths page of your instance

For more details on the available component options as well as how you can customize them, please visit the <SignUp /> and <SignIn /> component guides.

Next steps

You now have a working Remix + Clerk app. Going forward, you can:

Was this helpful?

Clerk Β© 2022