Session tasks
Tasks are pending requirements that users must complete after authentication, such as choosing an organization. When enabled in the Clerk Dashboard, these tasks are handled automatically within the <SignIn />
and <SignUp />
components.
Available tasks
Each task is identified by a unique . You can use these task keys to conditionally handle different requirements in your application logic.
The following table lists the available tasks and their corresponding keys.
Setting | Key | Description |
---|---|---|
Allow personal accounts | choose-organization | Disabled by default when enabling organizations, requires users to choose an organization after authenticating. When disabled, users can choose a personal account. |
Session states
After authentication, users enter one of three states:
- Signed-in: Authentication complete. Can access protected content or routes.
- Pending: Authentication complete, but session tasks incomplete. Can't access protected content or routes.
- Signed-out: Authentication failed or not attempted. Can't access protected content or routes.
When authenticating, sessions remain pending
until users complete the required tasks. By default, pending
sessions are treated as signed-out across Clerk's authentication context.
Implementation
Displaying tasks
Once enabled in the Clerk Dashboard, tasks are embedded by default within the <SignUp />
and <SignIn />
components. For more customization, you can opt out of using the <SignUp />
and <SignIn />
components and create custom pages for tasks.
The following table lists the available tasks and their corresponding components. See the linked reference guide for usage instructions.
If the prebuilt components don't meet your specific needs or if you require more control over the logic, you can also build your own UI using the Session.currentTask
property to check if the user has pending session tasks. Refer to the custom flows documentation for specific implementation guides.
import { useSession } from '@clerk/clerk-react'
const { session } = useSession()
if (session?.currentTask) {
// Check for pending tasks and display custom UI to help users resolve them
// See https://clerk.com/docs/custom-flows/overview#session-tasks
console.log(session?.currentTask)
}
if (window.Clerk.session.currentTask) {
// Check for pending tasks and display custom UI to help users resolve them
// See https://clerk.com/docs/custom-flows/overview#session-tasks
console.log(window.Clerk.session.currentTask)
}
Redirecting to tasks
When users have pending session tasks, you can redirect them to specific pages or components to complete these requirements. This is useful when you want to handle session tasks outside of the default <SignIn />
and <SignUp />
components.
Using the taskUrls
option
The taskUrls
option allows you to specify custom URL paths where users are redirected after sign-up or sign-in when specific session tasks need to be completed. This allows you to still use <SignIn />
and <SignUp />
but have tasks with custom pages.
Configure the taskUrls
option in your root layout to specify where users should be redirected for different session tasks.
import { ClerkProvider } from '@clerk/nextjs'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider
publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY}
taskUrls={{
'choose-organization': '/onboarding/choose-organization',
}}
>
{children}
</ClerkProvider>
)
}
Create a custom page that imports the TaskChooseOrganization
component to handle the task.
import { TaskChooseOrganization } from '@clerk/nextjs'
export default function ChooseOrganizationPage() {
return <TaskChooseOrganization redirectUrlComplete="/dashboard" />
}
Using the RedirectToTasks
control component
The <RedirectToTasks />
control component redirects users to the appropriate task page when they have pending session tasks.
import { SignedOut, RedirectToTasks } from '@clerk/nextjs'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<SignedOut>
<RedirectToTasks />
</SignedOut>
{children}
</>
)
}
Middleware-based redirects
For auth.protect()
, signed-out users will be redirected to the sign-in page. In the following example, pending
users will be redirected to the sign-in page, where the <SignIn />
component will prompt them to fulfill the session tasks, which in this case is selecting or creating an organization. Once finished, their session will move from pending
to an active
(signed-in) state.
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)'])
export default clerkMiddleware(async (auth, req) => {
// pending users won't be able to access protected routes
// and will be redirected to the sign-in page
if (isProtectedRoute(req)) await auth.protect()
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
For auth().userId
, it would return null
if the user has a pending
session. Pending users will be redirected to the sign-in page, where the <SignIn />
component will prompt them to fulfill the session tasks. Once finished, their session will move from pending
to a signed-in
state.
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)'])
export default clerkMiddleware(async (auth, req) => {
const { userId, redirectToSignIn } = await auth()
// pending users will not have a `userId`
// and will be redirected to the sign-in page
if (!userId && isProtectedRoute(req)) {
return redirectToSignIn()
}
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
Session handling
You can check the current authentication state using the Clerk.isSignedIn
property. By default, pending
sessions are treated as signed-out across Clerk's authentication context. Some control components and authentication utilities accept a treatPendingAsSignedOut
prop to control how pending
sessions are handled:
true
(default): Treatspending
sessions as signed-out. Users can't access protected content or routes.false
: Treatspending
sessions as signed-in. Users can access protected content or routes.
Control components
The <Protect /> component protects content or even entire routes based on a user's authentication state. It will render its children if the user's state is signed-in. It accepts a fallback
prop that will be rendered if the user's state is signed-out.
If the user's state is pending
, they will see the fallback
content because, by default, pending
sessions are treated as signed-out.
export default function Page() {
return (
<Protect fallback={<p>Signed-out and pending users can see this.</p>}>
<p>Only signed-in users can see this.</p>
</Protect>
)
}
If the user's state is pending
, they will see the protected content because treatPendingAsSignedOut
is set to false
.
export default function Page() {
return (
<Protect
treatPendingAsSignedOut={false}
fallback={<p>Users that are signed-out can see this.</p>}
>
<p>Users that are signed-in or pending can see this.</p>
</Protect>
)
}
The <SignedOut /> component renders its children if the user's authentication state is signed-out.
If the user's state is pending
, they will see the content of the component because, by default, pending
sessions are treated as signed-out.
export default function Page() {
return (
<SignedOut>
<p>Users that are signed-out or pending will see this.</p>
</SignedOut>
)
}
If the user's state is pending
, they won't see the content of the component because treatPendingAsSignedOut
is set to false
.
export default function Page() {
return (
<SignedOut treatPendingAsSignedOut={false}>
<p>Users that are signed-out will see this.</p>
</SignedOut>
)
}
The <SignedIn /> component renders its children if the user's authentication state is signed-in.
If the user's state is pending
, they won't see the content of the component because, by default, pending
sessions are treated as signed-out.
export default function Page() {
return (
<SignedIn>
<p>Users that are signed-in will see this.</p>
</SignedIn>
)
}
If the user's state is pending
, they will see the content of the component because treatPendingAsSignedOut
is set to false
.
export default function Page() {
return (
<SignedIn treatPendingAsSignedOut={false}>
<p>Users that are signed-in or pending will see this.</p>
</SignedIn>
)
}
Authentication utilities
The useAuth()
hook and helpers that access the , such as getAuth()
or request.auth
, will return null
if the user has a pending
session. Most utilities accept a treatPendingAsSignedOut
option that defaults to true
. You can pass false
to treat pending
sessions as signed-in.
Example: Personal accounts disabled
When organizations are enabled, personal accounts are disabled by default and your users will be required to select or create an organization after authenticating. Until completed, their session remains pending
. Pages that are protected using Clerk's protection utilities will treat the user's session as signed-out.
For useAuth()
, userId
will be null
if the user has a pending
session.
export default function Dashboard() {
const { isSignedIn, userId } = useAuth()
if (!userId) {
return (
<p>
User has no session or a pending session. They either need to sign in, or they need to
complete tasks by selecting or creating an organization.
</p>
)
}
return (
<p>
<p>User has a valid session and {orgId} is defined</p>
</p>
)
}
For auth().userId
, it would return null
if the user has a pending
session.
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
const { userId, orgId } = await auth()
if (!userId) {
return (
<p>
User has no session or a pending session. They either need to sign in, or they need to
complete pending session tasks by selecting or creating an organization.
</p>
)
}
return (
<p>
<p>User has a valid session and {orgId} is defined</p>
</p>
)
}
By default, users with a pending
session are treated as signed-out, and their userId
will not be available. However, in some cases, you may want to access the user's ID even if their session is still pending
. In these cases, you can set treatPendingAsSignedOut
to false
, which will treat pending
sessions as signed-in and allow you to access the userId
.
import { auth } from '@clerk/nextjs/server'
export const POST = async () => {
// `treatPendingAsSignedOut` is set to `false` to allow access to the `userId` for pending sessions
const { userId, has } = await auth({ treatPendingAsSignedOut: false })
// Check if the user is signed-out
if (!userId) {
return Response.json({ error: 'User is signed-out' }, { status: 401 })
}
// Now the pending user's `userId` can be used for your use case
// This is a basic example of creating a resource using the `userId`
try {
const newResource = await resources.create({
userId,
})
return Response.json({ data: newResource }, { status: 201 })
} catch (error) {
return Response.json({ error: 'Failed to create resource' }, { status: 500 })
}
}
Feedback
Last updated on