Start by creating a new Create React App app.
npx create-react-app yourapp# oryarn create react-app yourapp
For more information about these commands, please reference the Create React App documentation.
Install Clerk's NPM package for React applications.
# From your application's root directorycd yourappnpm install @clerk/clerk-react# oryarn add @clerk/clerk-react
Clerk requires every page to be wrapped in the <ClerkProvider>
context. In Create React App, we add this in src/App.js.
In the code below, we've also added a sign in requirement, and show a greeting when a user is signed in.
src/App.jsimport { useEffect } from "react";import {ClerkProvider,SignedIn,SignedOut,UserButton,useUser,} from "@clerk/clerk-react";// Replace with your instance settingsconst clerkFrontendApi = "auth.abc123.lcl.dev";const clerkSignInURL = "https://accounts.abc123.lcl.dev/sign-in";function App() {return (<ClerkProvider frontendApi={clerkFrontendApi}><SignedIn><UserButton /><Greeting /></SignedIn><SignedOut><RedirectToSignIn /></SignedOut></ClerkProvider>);}function Greeting() {const { firstName } = useUser();return <div>Hello, {firstName}!</div>;}function RedirectToSignIn() {useEffect(() => {window.location.href = clerkSignInURL;});return null;}export default App;
A common next step is to add a router. Here we use React Router to add public and protected routes to our application.
Before using this code, you must install React Router:
npm install react-router-dom# oryarn add react-router-dom
This is just one example of how authentication can be handled with Clerk. Feel free to adjust the strategy to better serve your use case!
src/App.jsimport { useEffect } from "react";import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";import {ClerkProvider,SignedIn,SignedOut,UserButton,useUser,} from "@clerk/clerk-react";// Replace with your instance settingsconst clerkFrontendApi = "auth.abc123.lcl.dev";const clerkSignInURL = "https://accounts.abc123.lcl.dev/sign-in";function App() {return (<Router><ClerkProvider frontendApi={clerkFrontendApi}><Switch>{/* Public routes, accesible whether or not a user is signed in */}<Route path="/public"><div>Reached the public route. <Link to="/">Return home.</Link></div></Route>{/* Private routes, accesible only if a user is signed in */}<PrivateRoute path="/private"><div>Reached the private route. <Link to="/">Return home.</Link></div></PrivateRoute>{/* Catch-all route will render if no other route renders */}<Route><SignedIn><UserButton /><Greeting /><div>You are signed in. You can access both routes.</div><Navigation /></SignedIn><SignedOut><div>You are signed out. You can access the public route.</div><Navigation /></SignedOut></Route></Switch></ClerkProvider></Router>);}function PrivateRoute(props) {// If the route matches but the user is not signed in, redirect to /sign-inreturn (<><SignedIn><Route {...props} /></SignedIn><SignedOut><RedirectToSignIn /></SignedOut></>);}function Navigation() {return (<ul><li><Link to="/public">Public route</Link></li><li><Link to="/private">Private route</Link></li></ul>);}function Greeting() {const { firstName } = useUser();return <div>Hello, {firstName}!</div>;}function RedirectToSignIn() {useEffect(() => {window.location.href = clerkSignInURL;});return null;}export default App;
Use our guide for making backend requests to ensure your backend can determine the signed in user.
By default, Clerk hosts the SignIn, SignUp, and UserProfile components on the accounts.* subdomain of your root domain.
If you prefer, you can also "mount" these components directly in your application.
The code below uses the same logic as above, but with three additional changes:
We add public routes for SignIn and SignUp, and a private route for UserProfile.
We create a <ClerkProviderWithNavigate>
component that uses React Router's useHistory hook to pass a navigate prop to <ClerkProvider>
. This allows Clerk to navigate inside and between components without conflicting with React Router.
We replace our custom <RedirectToSignIn>
component with React Router's <Redirect>
component, since now the navigation is internal.
src/App.jsimport { useEffect } from "react";import {BrowserRouter as Router,Switch,Route,Link,useHistory,Redirect,} from "react-router-dom";import {ClerkProvider,SignedIn,SignedOut,UserButton,useUser,SignIn,SignUp,UserProfile,} from "@clerk/clerk-react";// Replace with your instance settingsconst clerkFrontendApi = "auth.abc123.lcl.dev";const clerkSignInPath = "/sign-in";function App() {return (<Router><ClerkProviderWithNavigate><Switch>{/* Public routes, accesible whether or not a user is signed in */}<Route path="/public"><div>Reached the public route. <Link to="/">Return home.</Link></div></Route><Route path="/sign-in/(.*)?"><SignIn routing="path" path="/sign-in" /></Route><Route path="/sign-up/(.*)?"><SignUp routing="path" path="/sign-up" /></Route>{/* Private routes, accesible only if a user is signed in */}<PrivateRoute path="/private"><div>Reached the private route. <Link to="/">Return home.</Link></div></PrivateRoute><PrivateRoute path="/user/(.*)?"><UserProfile routing="path" path="/user" /></PrivateRoute>{/* Catch-all route will render if no other route renders */}<Route><SignedIn><UserButton /><Greeting /><div>You are signed in. You can access both routes.</div><Navigation /></SignedIn><SignedOut><div>You are signed out. You can access the public route.</div><Navigation /></SignedOut></Route></Switch></ClerkProviderWithNavigate></Router>);}function Navigation() {return (<ul><li><Link to="/public">Public route</Link></li><li><Link to="/private">Private route</Link></li></ul>);}function Greeting() {const { firstName } = useUser();return <div>Hello, {firstName}!</div>;}function PrivateRoute(props) {// If the route matches but the user is not signed in, redirect to /sign-inreturn (<><SignedIn><Route {...props} /></SignedIn><SignedOut><Redirect to={clerkSignInPath} /></SignedOut></>);}function ClerkProviderWithNavigate({ children }) {const { push } = useHistory();return (<ClerkProviderfrontendApi={clerkFrontendApi}navigate={(to) => push(to)}>{children}</ClerkProvider>);}export default App;
The final step is to update your instance settings so that users will be defaulted to your mounted components instead of the "accounts" subdomain.
To change the settings, open your instance in the Dashboard and navigate to Settings → URLs and Redirects.