Skip to main content

Beta

This feature is currently in beta. Functionality may change before general availability. If you run into any issues, please reach out to our support team.

Agent Tasks provide a way to create authenticated sessions on behalf of users without going through the standard sign-in flow. When you create an Agent Task, Clerk returns a URL that, when visited, creates a session for the specified user and redirects to the URL of your choice.

This is useful for:

  • Automated end-to-end testing where you need a signed-in user
  • AI agent workflows that act on behalf of a user

Create an Agent Task

Use the clerkClient.agentTasks.create() method to create an Agent Task. The returned url can then be visited to establish the session.

example.js
import { createClerkClient } from '@clerk/backend'

const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY })

async function createAgentTask(request) {
  // Use the `request.auth` object to access `isAuthenticated` and the user's ID
  const { isAuthenticated, userId } = request.auth

  // Protect the route from unauthenticated users
  if (!isAuthenticated) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const agentTask = await clerkClient.agentTasks.create({
    onBehalfOf: {
      userId,
    },
    permissions: '*',
    agentName: 'my-agent',
    taskDescription: 'Automated test login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  // agentTask.url is the URL to visit to authenticate the user
  return agentTask
}
app/api/example/route.ts
import { auth, clerkClient } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'

export async function POST() {
  // Use the `auth()` helper to access the `isAuthenticated` and the user's ID
  const { isAuthenticated, userId } = await auth()

  // Protect the route from unauthenticated users
  if (!isAuthenticated) {
    return new NextResponse('Unauthorized', { status: 401 })
  }

  // Instantiate the `clerkClient`
  const client = await clerkClient()

  // Use the `createAgentTask()` method to create the Agent Task
  const agentTask = await client.agentTasks.create({
    onBehalfOf: {
      userId,
    },
    permissions: '*',
    agentName: 'my-agent',
    taskDescription: 'Automated test login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  return NextResponse.json({ message: 'Agent Task created', agentTask })
}
src/api/example.ts
import type { APIRoute } from 'astro'
import { clerkClient } from '@clerk/astro/server'

export const POST: APIRoute = async (context) => {
  // Use the `locals.auth()` function to access the `isAuthenticated` and the user's ID
  const { isAuthenticated, userId } = context.locals.auth()

  // Protect the route from unauthenticated users
  if (!isAuthenticated) {
    return new Response('Unauthorized', { status: 401 })
  }

  // Use the `createAgentTask()` method to create the Agent Task
  const agentTask = await clerkClient(context).agentTasks.create({
    onBehalfOf: {
      userId,
    },
    permissions: '*',
    agentName: 'my-agent',
    taskDescription: 'Automated test login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  return new Response(JSON.stringify({ message: 'Agent Task created', agentTask }), { status: 200 })
}
public.ts
import { getAuth, clerkClient } from '@clerk/express'

app.post('/createAgentTask', async (req, res) => {
  // Use the `getAuth()` helper to access the `isAuthenticated` and the user's ID
  const { isAuthenticated, userId } = getAuth(req)

  // Protect the route from unauthenticated users
  if (!isAuthenticated) {
    res.status(401).json({ error: 'Unauthorized' })
    return
  }

  // Use the `createAgentTask()` method to create the Agent Task
  const agentTask = await clerkClient.agentTasks.create({
    onBehalfOf: {
      userId,
    },
    permissions: '*',
    agentName: 'my-agent',
    taskDescription: 'Automated test login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  res.status(200).json({ message: 'Agent Task created', agentTask })
})
src/routes/example.ts
import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
import { clerkClient, getAuth } from '@clerk/fastify'

export const exampleRoutes = (fastify: FastifyInstance) => {
  fastify.post('/createAgentTask', async (req: FastifyRequest, res: FastifyReply) => {
    // Use the `getAuth()` helper to access the `isAuthenticated` and the user's ID
    const { isAuthenticated, userId } = getAuth(req)

    // Protect the route from unauthenticated users
    if (!isAuthenticated) {
      return res.status(401).json({ error: 'Unauthorized' })
    }

    // Use the `createAgentTask()` method to create the Agent Task
    const agentTask = await clerkClient.agentTasks.create({
      onBehalfOf: {
        userId,
      },
      permissions: '*',
      agentName: 'my-agent',
      taskDescription: 'Automated test login',
      redirectUrl: 'http://localhost:3000/dashboard',
    })

    res.status(200).json({ message: 'Agent Task created', agentTask })
  })
}
server/api/example.ts
import { clerkClient } from '@clerk/nuxt/server'

export default defineEventHandler(async (event) => {
  // Use the `event.context.auth()` function to access the `isAuthenticated` and the user's ID
  const { isAuthenticated, userId } = event.context.auth()

  // Protect the route from unauthenticated users
  if (!isAuthenticated) {
    return createError({ statusCode: 401, statusMessage: 'Unauthorized' })
  }

  // Use the `createAgentTask()` method to create the Agent Task
  const agentTask = await clerkClient(event).agentTasks.create({
    onBehalfOf: {
      userId,
    },
    permissions: '*',
    agentName: 'my-agent',
    taskDescription: 'Automated test login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  return { message: 'Agent Task created', agentTask }
})
app/routes/example.tsx
import { clerkClient, getAuth } from '@clerk/react-router/server'
import type { Route } from './+types/example'

export async function action(args: Route.ActionArgs) {
  // Use the `getAuth()` helper to access the `isAuthenticated` and the user's ID
  const { isAuthenticated, userId } = await getAuth(args)

  // Protect the route from unauthenticated users
  if (!isAuthenticated) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  // Use the `createAgentTask()` method to create the Agent Task
  const agentTask = await clerkClient(args).agentTasks.create({
    onBehalfOf: {
      userId,
    },
    permissions: '*',
    agentName: 'my-agent',
    taskDescription: 'Automated test login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  return Response.json({ message: 'Agent Task created', agentTask })
}
app/routes/api/example.tsx
import { json } from '@tanstack/react-start'
import { createFileRoute } from '@tanstack/react-router'
import { auth, clerkClient } from '@clerk/tanstack-react-start/server'

export const ServerRoute = createFileRoute('/api/example')({
  server: {
    handlers: {
      POST: async () => {
        // Use the `auth()` helper to access the `isAuthenticated` and the user's ID
        const { isAuthenticated, userId } = await auth()

        // Protect the route from unauthenticated users
        if (!isAuthenticated) {
          return json({ error: 'Unauthorized' }, { status: 401 })
        }

        // Use the `createAgentTask()` method to create the Agent Task
        const agentTask = await clerkClient().agentTasks.create({
          onBehalfOf: {
            userId,
          },
          permissions: '*',
          agentName: 'my-agent',
          taskDescription: 'Automated test login',
          redirectUrl: 'http://localhost:3000/dashboard',
        })

        return json({ message: 'Agent Task created', agentTask })
      },
    },
  },
})

In Playwright tests, instantiate the client with createClerkClient() from @clerk/backend rather than importing clerkClient from your framework SDK (e.g., @clerk/nextjs/server). Framework SDK exports aren't available outside your app's request context.

e2e/app.spec.ts
import { createClerkClient } from '@clerk/backend'
import { test, expect } from '@playwright/test'

const clerkClient = createClerkClient({
  secretKey: process.env.CLERK_SECRET_KEY,
})

test('authenticated user flow', async ({ page }) => {
  const agentTask = await clerkClient.agentTasks.create({
    onBehalfOf: {
      userId: 'user_xxx',
      // or { identifier: 'test@example.com' }
    },
    permissions: '*',
    agentName: 'test-agent',
    taskDescription: 'test-login',
    redirectUrl: 'http://localhost:3000/dashboard',
  })

  await page.goto(agentTask.url)
  await expect(page.locator('header')).toContainText('Welcome')
})

Revoke an Agent Task

If you need to invalidate an Agent Task before it's used, you can revoke it.

Feedback

What did you think of this content?

Last updated on