βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β π shadcn/directory/clerk/clerk-docs/guides/development/making-requests β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β
A request is considered βauthenticatedβ when the backend can securely identify the user and device that is making the request. Reasons for making authenticated requests to the backend include:
To authenticate requests when using a Clerk SDK, you must pass Clerk's short-lived session token to your server. The session token contains cryptographically signed claims about the user's identity and authentication state. Read more about making requests.
The following headers are required for Clerk to authenticate a request. It contains information that Clerk uses to determine whether a request is in a signed in or signed out state, or if a handshake must be performed.
Authorization: This should include the user's session token as a Bearer token.AcceptHostOriginRefererSec-Fetch-DestUser-AgentX-Forwarded-HostX-Forwarded-Proto
CloudFront-Forwarded-ProtoTo make authenticated requests, the approach differs based on whether your client and server are on the same origin or different origins.
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.
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())
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.
<Tabs items={["Fetch", "Fetch with SWR", "Fetch with Tanstack Query"]}>
<Tab>
```jsx
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
}
```
</Tab>
<Tab>
```tsx
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)
}
```
</Tab>
<Tab>
When using [Tanstack Query](https://tanstack.com/query/v4/docs/react/overview) (formerly React Query), you'll need a query function that properly handles errors. The native [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) 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](https://tanstack.com/query/v4/docs/react/quick-start) for setup instructions.
```tsx
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>
}
```
</Tab>
</Tabs>
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.
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())
})()
In React-based applications, use the useAuth() hook to access the getToken() method.
<Tabs items={["Fetch", "Fetch with SWR", "Fetch with Tanstack Query"]}>
<Tab>
```js
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
}
```
</Tab>
<Tab>
```js
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)
}
```
</Tab>
<Tab>
The following example shows how to use [Tanstack Query](https://tanstack.com/query/v4/docs/react/overview) to create an authenticated query.
When using [Tanstack Query](https://tanstack.com/query/v4/docs/react/overview) (formerly React Query), you'll need a query function that properly handles errors. The native [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) 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](https://tanstack.com/query/v4/docs/react/quick-start) for setup instructions.
```tsx
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>
}
```
</Tab>
</Tabs>β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ