I successfully set up a next.js application with JWT authentication connected to a Spring Boot API (Next is used as a client). The implementation of the next.js app was influenced by this tutorial:
Key Dependencies: Axios: 0.24.0 Next: 12.0.7 React: 17.0.2 SWR: 1.1.0
In a page like [id].tsx, I utilize axios to make a request
const headers = api.defaults.headers;
const fetcher = (url: string) => axios.get(url, {headers}).then(res => res.data)
const router = useRouter()
const { id } = router.query
const path = process.env.API_URL + "events/" + id;
const { data } = useSWR<EventType>(path, fetcher);
... the rest of the component uses "data"...and after the component...
export async function getStaticPaths() {
return {
paths: [
'/events/[...id]',
],
fallback: true,
}
}
export default EventPage;
When dealing with "headers," I encountered a TypeScript error:
(property) AxiosRequestConfig<any>.headers?: AxiosRequestHeaders
Type 'HeadersDefaults' is not assignable to type 'AxiosRequestHeaders'.
Index signature for type 'string' is missing in type 'HeadersDefaults'.ts(2322)
index.d.ts(68, 3): The expected type comes from property 'headers' which is declared here on type 'AxiosRequestConfig<any>'
There is an api.ts file that creates the axios object used for all requests in the app
import Axios from "axios";
const api = Axios.create({
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
});
export default api;
This api is imported in [id].tsx
And the Authorization context is established in auth.tsx
import React, { createContext, useState, useContext, useEffect } from 'react'
import { useRouter } from "next/router";
import LoadingPage from '../pages/loading';
import api from '../services/api';
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [loading, setLoading] = useState<boolean>(true)
useEffect(() => {
async function loadUserFromStorage() {
const token = window.localStorage.getItem('jwtAuthToken')
if (token) {
api.defaults.headers['Authorization'] = `Bearer ${token}`
}
setLoading(false)
}
loadUserFromStorage()
}, [])
return (
<AuthContext.Provider value={{ loading }}>
{children}
</AuthContext.Provider>
)
}
export const useAuth = () => useContext(AuthContext)
export const ProtectRoute = ({ children }) => {
const auth = useAuth();
const router = useRouter();
if (
(auth.loading && router.pathname !== '/') ||
(router.pathname !== '/' && !window.localStorage.getItem('jwtAuthToken'))
) {
return <LoadingPage />;
}
return children;
};
The "auth.loading" also presents a type error that I am currently working on resolving.
All of these configurations are applied to the _app.js:
function MyApp({ Component, pageProps }) {
return (
<AuthProvider>
<ProtectRoute>
<Component {...pageProps} />
</ProtectRoute>
</AuthProvider>
);
}
Everything functions properly in development mode, but I am encountering difficulties when trying to build due to the type errors.