How to use JWT and useFetch to make authenticated API requests in Nuxt 3
In this tutorial, we will learn how to create a custom Nuxt 3 plugin that uses the useFetch
function to make authenticated API requests with error handling, useFetch
is a built-in function in Nuxt 3. We will use the defu
library to merge the default and custom options for the fetch request, and the useCookie
function to store and retrieve the access and refresh tokens.
Creating the plugin
We will create a custom hook called useIFetch
that takes a URL and an optional options object as parameters and returns the same result as the useFetch
function. The useIFetch
hook will:
- Use the
useCookie
function to get the access token from the cookie - Set the
baseURL
and theAuthorization
header for the fetch request - Use the
onResponse
option to handle the 401 (unauthorized) error by refreshing the token and retrying the request - Use the
defu
function to merge the default and custom options
To create the plugin, we will create a file called useIFetch.ts
in the plugins
folder of our Nuxt project, and add the following code:
import type { UseFetchOptions } from "#app";
import { defu } from "defu";
export async function useIFetch<T>(
url: string,
options: UseFetchOptions<T> = {}
) {
const accessToken = useCookie("accessToken");
const defaults: UseFetchOptions<T> = {
baseURL: "http://127.0.0.1:8000/",
key: url,
headers: accessToken.value
? { Authorization: `Bearer ${accessToken.value}` }
: {},
onResponse: async ({ response, options }) => {
if (response.status === 401) {
try {
const newToken = await refreshToken();
accessToken.value = newToken;
options.headers = { Authorization: `Bearer ${newToken}` };
useFetch(url, options as UseFetchOptions<T>);
} catch (error) {
console.error("Token refresh failed:", error);
}
}
},
};
const params = defu(options, defaults);
return useFetch(url, params);
}
async function refreshToken() {
const refreshToken = useCookie("refreshToken");
const { data, status } = await useFetch<{ access: string }>(
"http://127.0.0.1:8000/api/token/refresh/",
{
method: "POST",
body: { refresh: refreshToken.value },
}
);
if (status.value === "success") {
return data.value?.access;
} else {
throw new Error("Token refresh failed");
}
}
I have used Simple JWT to implement APIs.
Using the plugin
we can use the useIFetch
hook in any component or page, just like the useFetch
function. For example, we can fetch the user profile from the /api/profile/
endpoint like this:
<template>
<div>
<h1>User Profile</h1>
<div v-if="pending">Loading...</div>
<div v-else-if="error">Error: {{ $fetchState.error.message }}</div>
<div v-else>
<p>Username: {{ data.username }}</p>
<p>Email: {{ data.email }}</p>
</div>
</div>
</template>
<script setup lang="ts">
interface Profile {
username: string;
email: string;
}
const { data, pending, error } = useIFetch<Profile>("/api/profile/");
</script>
Conclusion
In this tutorial, we learned how to create a custom Nuxt 3 plugin that uses the useFetch
function to make authenticated API requests with error handling. We also learned how to use the defu
library to merge the default and custom options for the fetch request, and the useCookie
function to store and retrieve the access and refresh tokens. We hope you found this tutorial useful and informative. Please let me know in the comments below if you have any questions or feedback.
Happy coding!