Skip to main content
Docs

Making requests

To make authenticated requests, the approach differs based on whether your client and server are on the same origin or different origins.

Same-origin requests

If your client and server are on the same origin (e.g. making an API call to foo.com/api from JavaScript running on foo.com), the session token is automatically passed to the backend in a cookie. This means that all requests to same-origin endpoints are authenticated by default.

Vanilla JavaScript

You can use the native browser Fetch API as you normally would and the request will be authenticated.

fetch('/api/foo').then((res) => res.json())

React-based applications

You can use the native browser Fetch API as you normally would and the request will be authenticated. But when a tab loses focus, and data must be fetched in the background, the session token cookie is not automatically included. You'll need to explicitly pass the session token as a Bearer token in the Authorization header.

Use the useAuth() hook's getToken() method to get the session token. Since getToken() returns a Promise, you'll need to await its resolution before making the request.

export default async function useFetch() {
  // Use `useAuth()` to access the `getToken()` method
  const { getToken } = useAuth()

  // Use `getToken()` to get the current session token
  const token = await getToken()

  const authenticatedFetch = async (...args) => {
    return fetch(...args, {
      headers: { Authorization: `Bearer ${token}` }, // Include the session token as a Bearer token in the Authorization header
    }).then((res) => res.json())
  }
  return authenticatedFetch
}
import useSWR from 'swr'

export default async function useClerkSWR(url: string) {
  // Use `useAuth()` to access the `getToken()` method
  const { getToken } = useAuth()

  // Use `getToken()` to get the current session token
  const token = await getToken()

  const fetcher = async (...args: [RequestInfo]) => {
    return fetch(...args, {
      headers: { Authorization: `Bearer ${token}` }, // Include the session token as a Bearer token in the Authorization header
    }).then((res) => res.json())
  }

  return useSWR(url, fetcher)
}

When using Tanstack Query (formerly React Query), you'll need a query function that properly handles errors. The native Fetch API doesn't throw errors for non-200 responses, so you'll need to add explicit error handling.

Note

Your application must be wrapped in a <QueryClientProvider /> component with a configured QueryClient instance. See the Tanstack Query docs for setup instructions.

import { useQuery } from '@tanstack/react-query'
import { useAuth } from '@clerk/nextjs'

// Define your query keys as constants to avoid typos
export const queryKeys = {
  foo: ['foo'] as const,
  // Add other query keys as needed
}

// Define the response type for type safety
interface FooResponse {
  // Add your response type here
  id: string
  name: string
}

export function useFooQuery() {
  // Use `useAuth()` to access the `getToken()` method
  const { getToken } = useAuth()

  return useQuery({
    queryKey: queryKeys.foo,
    queryFn: async (): Promise<FooResponse> => {
      // Use `getToken()` to get the current session token
      const token = await getToken()

      // Make the request
      const response = await fetch('/api/foo', {
        headers: {
          Authorization: `Bearer ${token}`, // Include the session token as a Bearer token in the Authorization header
          'Content-Type': 'application/json',
        },
      })

      if (!response.ok) {
        // Include status code and status text in error message
        throw new Error(`API Error: ${response.status} ${response.statusText}`)
      }

      const data = await response.json()
      return data as FooResponse
    },
    // Add common configuration options
    retry: 2,
    staleTime: 5 * 60 * 1000, // 5 minutes
  })
}

// Usage in component:
function MyComponent() {
  const { data, isLoading, error } = useFooQuery()

  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!data) return null

  return <div>{data.name}</div>
}

Cross-origin requests

If your client and server are on different origins (e.g. making an API call to a server on api.foo.com from JavaScript running on a client at foo.com), the session token needs to be passed as a Bearer token in the Authorization header.

You can retrieve the session token using the getToken() method. Since getToken() returns a Promise, you'll need to await its resolution before making the request.

Vanilla JavaScript

In JavaScript applications, use the global Clerk.session object to access the getToken() method.

(async () => {
  fetch('/api/foo', {
    headers: {
      Authorization: `Bearer ${await Clerk.session.getToken()}`,
    },
  }).then((res) => res.json())
})()

React-based applications

In React-based applications, use the useAuth() hook to access the getToken() method.

export default async function useFetch() {
  // Use `useAuth()` to access the `getToken()` method
  const { getToken } = useAuth()

  // Use `getToken()` to get the current session token
  const token = await getToken()

  const authenticatedFetch = async (...args) => {
    return fetch(...args, {
      headers: { Authorization: `Bearer ${token}` }, // Include the session token as a Bearer token in the Authorization header
    }).then((res) => res.json())
  }

  return authenticatedFetch
}
import useSWR from 'swr'
import { useAuth } from '@clerk/nextjs'

export default async function useClerkSWR(url) {
  // Use `useAuth()` to access the `getToken()` method
  const { getToken } = useAuth()

  // Use `getToken()` to get the current session token
  const token = await getToken()

  const fetcher = async (...args) => {
    return fetch(...args, {
      headers: { Authorization: `Bearer ${token}` }, // Include the session token as a Bearer token in the Authorization header
    }).then((res) => res.json())
  }

  return useSWR(url, fetcher)
}

The following example shows how to use Tanstack Query to create an authenticated query.

When using Tanstack Query (formerly React Query), you'll need a query function that properly handles errors. The native Fetch API doesn't throw errors for non-200 responses, so you'll need to add explicit error handling.

Note

Your application must be wrapped in a <QueryClientProvider /> component with a configured QueryClient instance. See the Tanstack Query docs for setup instructions.

import { useQuery } from '@tanstack/react-query'
import { useAuth } from '@clerk/nextjs'

// Define your query keys as constants to avoid typos
export const queryKeys = {
  foo: ['foo'] as const,
  // Add other query keys as needed
}

// Define the response type for type safety
interface FooResponse {
  // Add your response type here
  id: string
  name: string
}

export function useFooQuery() {
  // Use `useAuth()` to access the `getToken()` method
  const { getToken } = useAuth()

  return useQuery({
    queryKey: queryKeys.foo,
    queryFn: async (): Promise<FooResponse> => {
      // Use `getToken()` to get the current session token
      const token = await getToken()

      // Make the request
      const response = await fetch('/api/foo', {
        headers: {
          Authorization: `Bearer ${token}`, // Include the session token as a Bearer token in the Authorization header
          'Content-Type': 'application/json',
        },
      })

      if (!response.ok) {
        // Include status code and status text in error message
        throw new Error(`API Error: ${response.status} ${response.statusText}`)
      }

      const data = await response.json()
      return data as FooResponse
    },
    // Add common configuration options
    retry: 2,
    staleTime: 5 * 60 * 1000, // 5 minutes
  })
}

// Usage in component:
function MyComponent() {
  const { data, isLoading, error } = useFooQuery()

  if (isLoading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!data) return null

  return <div>{data.name}</div>
}

Feedback

What did you think of this content?

Last updated on