Tasks after sign-up/sign-in
Session 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 SessionTask['key']. 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.
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.
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. To access the Session.currentTask property, you can use either the useSession() hook for React-based applications or window.Clerk for other frameworks.
const { session } = useSession()
if (session?.currentTask) {
  // Check for pending tasks and display custom UI to help users resolve them
  // See https://clerk.com/docs/guides/development/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/guides/development/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.
The taskUrls option is available wherever you initialize the Clerk integration. For most SDKs, it's <ClerkProvider>.
<ClerkProvider
  taskUrls={{
    'choose-organization': '/onboarding/choose-organization',
  }}
>
  {children}
</ClerkProvider>Then, create a page at that URL path that imports the <TaskChooseOrganization /> component to handle the task.
export default function Page() {
  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.
<>
  <SignedOut>
    <RedirectToTasks />
  </SignedOut>
</>Middleware-based redirects
You can use the isAuthenticated property in middleware to protect routes. By default, it will return false if the user has a pending session. Then, you can handle how to respond to pending users, such as redirecting them to the sign-in page using the redirectToSignIn() method.
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)'])
export default clerkMiddleware(async (auth, req) => {
  const { isAuthenticated, redirectToSignIn } = await auth()
  // `isAuthenticated` will be `false` for pending users
  // and pending users won't be able to access protected routes
  if (!isAuthenticated && isProtectedRoute(req)) {
    // Add logic to handle pending users
    // This example redirects pending users to the sign-in page
    // so they can fulfill the session tasks
    return redirectToSignIn()
  }
})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. 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)(.*)',
  ],
}Session handling
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): Treats- pendingsessions as signed-out. Users can't access protected content or routes.
- false: Treats- pendingsessions 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 Auth object, 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(), isSignedIn will be false and userId and orgId will be null if the user has a pending session.
export default function Dashboard() {
  const { isSignedIn, userId, orgId } = useAuth()
  if (!isSignedIn) {
    return (
      <p>
        User has no session, or has a pending session. They either need to sign in, or they need to
        complete tasks by selecting or creating an organization.
      </p>
    )
  }
  return (
    <p>
      User {userId} has a valid session and {orgId} is defined
    </p>
  )
}For helpers that access the Auth object, isAuthenticated would return false and userId and orgId would return null if the user has a pending session. This example uses the Next.js-specific auth() helper, but you can use the comments in the example to help you adapt it to your SDK.
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
  // The `Auth` object gives you access to properties like `isAuthenticated` and `userId`
  // Accessing the `Auth` object differs depending on the SDK you're using
  // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object
  const { isAuthenticated, userId, orgId } = await auth()
  if (!isAuthenticated) {
    return (
      <p>
        User has no session, or has 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>
      User {userId} has a valid session and {orgId} is defined
    </p>
  )
}Example: Accessing the userId for pending sessions
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. This example uses the Next.js-specific auth()
import { auth } from '@clerk/nextjs/server'
export const POST = async () => {
  // `treatPendingAsSignedOut` is set to `false` to allow access to the `userId` for pending sessions
  // Accessing the `Auth` object differs depending on the SDK you're using
  // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object
  const { isAuthenticated, userId, has } = await auth({ treatPendingAsSignedOut: false })
  // Check if the user is signed-out
  if (!isAuthenticated) {
    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