Skip to main content
Docs

Session tasks

Warning

This guide is for users who want to build a . To use a prebuilt UI, use the Account Portal pages or prebuilt components.

Session tasks are pending requirements that users must complete after authentication, such as choosing an Organization. These tasks ensure that users meet all requirements before gaining full access to your application.

When enabled in the Clerk Dashboard, these tasks are handled automatically within the <SignIn /> and <SignUp /> components. If the prebuilt components don't meet your specific needs or if you require more control over the logic, you can opt out of using the <SignUp /> and <SignIn /> components and create a to display tasks.

This guide demonstrates how to use the Clerk API to build a custom user interface for handling session tasks.

Available tasks

Each task is identified by a unique SessionTask['key']JavaScript Icon. 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.

SettingKeyDescription
Allow Personal Accountschoose-organizationDisabled by default when enabling Organizations . When disabled, users are required to choose an Organization after authenticating. When enabled, users can choose a instead of an Organization.
Force password resetreset-passwordEnabled by default . When enabled, the user is required to reset their password on their next sign-in if their password is marked as compromised.

Detect pending session tasks

First, you need to tell your app where to redirect users when they have pending session tasks.

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.

Configure the taskUrls option on the <ClerkProvider> component.

<ClerkProvider
  taskUrls={{
    'choose-organization': '/session-tasks/choose-organization',
    'reset-password': '/session-tasks/reset-password',
  }}
>
  {children}
</ClerkProvider>

Configure the taskUrls option on the clerk()Astro Icon integration.

astro.config.mjs
import { defineConfig } from 'astro/config'
import node from '@astrojs/node'
import clerk from '@clerk/astro'

export default defineConfig({
  integrations: [
    clerk({
      taskUrls: {
        'choose-organization': '/session-tasks/choose-organization',
        'reset-password': '/session-tasks/reset-password',
      },
    }),
  ],
  adapter: node({ mode: 'standalone' }),
  output: 'server',
})

Configure the taskUrls option on the clerk.load()JavaScript Icon method.

main.ts
import { Clerk } from '@clerk/clerk-js'

const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

const clerk = new Clerk(clerkPubKey)
await clerk.load({
  taskUrls: {
    'choose-organization': '/session-tasks/choose-organization',
    'reset-password': '/session-tasks/reset-password',
  },
})

Configure the taskUrls option on the clerkPlugin()Vue.js Icon integration.

src/main.ts
import { createApp } from 'vue'
import './styles.css'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

if (!PUBLISHABLE_KEY) {
  throw new Error('Add your Clerk publishable key to the .env.local file')
}

const app = createApp(App)
app.use(clerkPlugin, {
  publishableKey: PUBLISHABLE_KEY,
  taskUrls: {
    'choose-organization': '/session-tasks/choose-organization',
    'reset-password': '/session-tasks/reset-password',
  },
})
app.mount('#app')

Configure the taskUrls option on the defineNuxtConfig()Nuxt.js Icon integration.

nuxt.config.ts
export default defineNuxtConfig({
  compatibilityDate: '2025-07-15',
  devtools: { enabled: true },
  modules: ['@clerk/nuxt'],
  clerk: {
    taskUrls: {
      'choose-organization': '/session-tasks/choose-organization',
      'reset-password': '/session-tasks/reset-password',
    },
  },
})

Configure the taskUrls option on the clerkPlugin()Fastify Icon integration.

src/main.ts
import Fastify from 'fastify'
import { clerkPlugin } from '@clerk/fastify'

const fastify = Fastify({ logger: true })

fastify.register(clerkPlugin, {
  taskUrls: {
    'choose-organization': '/session-tasks/choose-organization',
    'reset-password': '/session-tasks/reset-password',
  },
})

Display tasks

Now, the user will be redirected to the URL you've set with the taskUrls option. You need to display the appropriate task UI based on the task that the user needs to complete. If you were using the prebuilt components, you would simply render the appropriate component based on the task. However, since you're building a custom flow, you need to build the UI yourself. You can use the custom flow guide associated with the task to help get you started:

Session taskCustom flow guide
choose-organizationOrganization switcher guide
reset-passwordReset password guide

Protect routes

What if your user exits the authentication or session task flow before completing their tasks and doesn't know how to get to the appropriate page to complete their session tasks? What if your user is navigating through your app as a pending user and can't figure out why they can't access certain content?

If a user's authentication or session task flow is interrupted and they aren't able to complete the tasks, you can use the <RedirectToTasks /> component to redirect them to the appropriate task page so they can complete the tasks and move their session to an active (signed-in) state. This component will redirect users based on the URL's you've set with the taskUrls option.

In the following example, the <RedirectToTasks /> component is used to protect a page. Users can't access this page until they complete their pending session tasks. You can also wrap your entire application in the <RedirectToTasks /> component, or place it in your application's layout file, so that users can't access any of your app until they complete their pending session tasks.

In the following example, the <RedirectToTasks /> component is used in the app's layout file so that users can't access any of the app until they complete their pending session tasks. However, you can also use the <RedirectToTasks /> component to protect a single page or route group.

app/layout.tsx
import { RedirectToTasks } from '@clerk/nextjs'

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <>
      <RedirectToTasks />
      {children}
    </>
  )
}
pages/index.tsx
import { RedirectToTasks } from '@clerk/clerk-react'

export default function Page() {
  return <RedirectToTasks />
}
app/routes/home.tsx
import { RedirectToTasks } from '@clerk/react-router'

export default function Home() {
  return <RedirectToTasks />
}

Note

This component relies on React Router for navigation. Ensure that you have integrated React Router into your Chrome Extension application before using it. Learn how to add React Router to your Chrome ExtensionGoogle Chrome Icon.

src/routes/home.tsx
import { RedirectToTasks } from '@clerk/chrome-extension'

export default function Home() {
  return <RedirectToTasks />
}
app/routes/index.tsx
import { RedirectToTasks } from '@clerk/tanstack-react-start'
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/')({
  component: Home,
})

function Home() {
  return <RedirectToTasks />
}
App.vue
<script setup lang="ts">
import { RedirectToTasks } from '@clerk/vue'
</script>

<template>
  <RedirectToTasks />
</template>
App.vue
<script setup lang="ts">
// Components are automatically imported
</script>

<template>
  <RedirectToTasks />
</template>

FAQ

What is the navigate parameter in setActive() doing?

In the authentication custom flows, such as the email/password custom flow, there's a step where you set the session to active using setActive(). If there are pending session tasks, the session won't actually be set as active. It will be in a pending state until all tasks are completed. By default, pending sessions are treated as signed-out across Clerk's authentication context, so the pending user won't be able to access protected content or routes. Therefore, this is the step where you should check for pending session tasks and redirect to the appropriate task page.

await setActive({
  session: signInAttempt.createdSessionId,
  navigate: async ({ session }) => {
    // Check for tasks and navigate to custom UI to help users resolve them
    // See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
    if (session?.currentTask) {
      console.log(session?.currentTask)
      router.push(`/session-tasks/${session?.currentTask.key}`)
      return
    }

    router.push('/')
  },
})

However, if you've set the taskUrls option on your Clerk integration, it will override the navigate behavior and will redirect the user to whatever URL path you've set for the task. It's recommended to rely on the taskUrls option so that you can maintain the task URLs in one place (your Clerk integration). However, the navigate parameter is still useful and can be used as a fallback.

Feedback

What did you think of this content?

Last updated on

GitHubEdit on GitHub