Authorization

Learn how to use convenience authorization helpers callApi provides

CallApi provides convenient authorization helpers via the auth property, making it easy to add authentication headers to your requests without manually constructing Authorization headers.

Bearer

Since Bearer is the most common authorization type, passing a string to auth automatically generates a Bearer Authorization header. You can also use an object with a bearer property.

api.ts
import { createFetchClient } from "@zayne-labs/callapi";

// Passing a string
const callBackendApi = createFetchClient({
	baseURL: "http://localhost:3000",
	auth: "my-token", 
});

// Passing an object
const result = await callBackendApi("/users/123", {
	auth: {
		type: "Bearer",
		value: "my-token",
	},
});

The above is equivalent to writing the following with Fetch:

fetch("http://localhost:3000/users/123", {
	headers: {
		Authorization: `Bearer my-token`,
	},
});

You can also pass a function that returns a string or a promise that resolves to a string. This is useful for retrieving tokens dynamically:

api.ts
import { createFetchClient } from "@zayne-labs/callapi";

const callBackendApi = createFetchClient({
	baseURL: "http://localhost:3000",
});

const result = callBackendApi("/users/123", {
	auth: {
		type: "Bearer",
		value: () => authStore.getToken(),
	},
});

The function will be called only once when the request is made. If it returns undefined or null, the header will not be added to the request. This allows for conditional authentication.

Token

Similar to Bearer authorization, but uses Token as the header prefix instead of Bearer.

api.ts
import { createFetchClient } from "@zayne-labs/callapi";

const callBackendApi = createFetchClient({
	baseURL: "http://localhost:3000",
	auth: {
		type: "Token",
		value: "my-token",
	},
});

const result = await callBackendApi("/users/123");

The above is equivalent to writing the following with Fetch:

fetch("http://localhost:3000/users/123", {
	headers: {
		Authorization: `Token my-token`,
	},
});

Basic

Basic authentication adds username and password to the Authorization header, automatically base64 encoded.

api.ts
import { createFetchClient } from "@zayne-labs/callapi";

const callBackendApi = createFetchClient({
	baseURL: "http://localhost:3000",
	auth: {
		type: "Basic",
		username: "my-username",
		password: "my-password",
	},
});

You can also pass async getter functions for the username and password fields.

const { data } = await callApi("/api/data", {
	auth: {
		type: "Basic",
		username: async () => await getUsername(),
		password: async () => await getPassword(),
	},
});

Custom

For custom authorization schemes not supported by default, use the Custom type with prefix and value properties.

api.ts
import { createFetchClient } from "@zayne-labs/callapi";

const callBackendApi = createFetchClient({
	baseURL: "http://localhost:3000",
	auth: {
		type: "Custom",
		prefix: "SomePrefix",
		value: "my-token",
	},
});

const result = await callBackendApi("/users/123");

The above is equivalent to writing the following with Fetch:

fetch("http://localhost:3000/users/123", {
	headers: { Authorization: `SomePrefix my-token` },
});

Advanced Examples

Refreshing Tokens

A common use case for auth is combining it with error hooks to implement automatic session recovery or token refreshing.

Since the auth function is called right before every request, and manual refetch() preservation is built-in, you can handle 401 Unauthorized errors seamlessly:

api.ts
import { createFetchClient } from "@zayne-labs/callapi";

const api = createFetchClient({
	baseURL: "https://api.example.com",

	auth: () => getAccessToken(),

	onResponseError: async ({ response, options }) => {
		if (response.status === 401) {
			const newToken = await refreshToken();

			localStorage.setItem("token", newToken);

			options.refetch();
		}
	},
});

Conditional Auth

Conditionally trigger authentication by returning null or undefined from your auth function when the user is not authenticated:

api.ts
const client = createFetchClient({
	baseURL: "https://api.example.com",

	auth: async () => {
		// Only add auth if user is logged in
		const isLoggedIn = await checkAuthStatus();

		// Returning null means no auth header will be added
		return isLoggedIn ? await getToken() : null;
	},
});

// Or dynamically per-request
async function makeRequest(endpoint: string, requiresAuth: boolean) {
	return callApi(endpoint, {
		auth: requiresAuth ? () => getToken() : undefined,
	});
}

Global Auth with Override

Define a global authentication strategy when creating a client and override or disable it for specific requests:

api.ts
const client = createFetchClient({
	baseURL: "https://api.example.com",
	auth: () => getSessionToken(),
});

// Uses the global auth token
const userData = await client("/api/user");

// Override with a different token for a specific request
const adminData = await client("/api/admin", {
	auth: () => getAdminToken(),
});

// Disable auth entirely for a specific request
const publicData = await client("/api/public", {
	auth: undefined,
});
Edit on GitHub

Last updated on

On this page