This will transparently handle authentication.
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
+import api from "@/api"
import type { User } from "@/types/User"
-import { fetchWithAuth } from "@/utils/fetchWithAuth"
interface AuthResponse {
access_token: string;
Access Token
*/
-function getAccessToken(): string | null {
+export function getAccessToken(): string | null {
return localStorage.getItem("token");
}
*/
export async function authenticateUser(username: string, password: string): Promise<User> {
- const response = await fetch("/api/v1/auth/user", {
- method : "POST",
-
- // Headers
- headers : {
- "Content-Type" : "application/x-www-form-urlencoded",
- },
-
- // Body
- body : new URLSearchParams({
+ try {
+ const params = new URLSearchParams({
username : username,
password : password,
- }),
- });
- if (!response.ok) {
- throw new Error("Invalid username or password");
- }
+ })
+
+ const response = await api.post("/v1/auth/user", params, {
+ headers: {
+ "Content-Type" : "application/x-www-form-urlencoded",
+ },
+ })
- // Parse the response
- const data: AuthResponse = await response.json();
+ const data: AuthResponse = response.data;
- // Store the access token
- setAccessToken(data.access_token);
+ // Store the access token from response
+ setAccessToken(data.access_token)
- // Fetch the logged in user
- return await fetchCurrentUser();
+ // Fetch and return the logged in user
+ return await fetchCurrentUser()
+ } catch (error) {
+ throw new Error("Invalid username or password")
+ }
}
/*
Returns the currently logged in user
*/
export async function fetchCurrentUser(): Promise<User> {
- const res = await fetchWithAuth("/api/v1/auth/whoami");
- if (!res.ok)
- throw new Error("Failed to load user");
-
- return res.json();
+ try {
+ const response = await api.get("/v1/auth/whoami")
+ return response.data
+ } catch (error) {
+ throw new Error("Failed to load user")
+ }
}
+import api from "@/api"
import type { Builder } from "@/types/Builder";
+// Fetch all builders
export async function fetchBuilders(): Promise<Builder[]> {
- // Fetch all builders
- const response = await fetch("/api/v1/builders");
- if (!response.ok)
- throw new Error("Failed to fetch builders");
-
- return response.json();
+ try {
+ const response = await api.get("/v1/builders");
+ return response.data;
+ } catch (error) {
+ throw new Error("Failed to load builders");
+ }
}
--- /dev/null
+import axios from "axios"
+
+// Fetch authentication
+import { useAuthStore } from "@/stores/auth"
+
+// API Authentication
+import { getAccessToken } from "@/api/auth"
+
+// Create a new API client
+const api = axios.create({
+ baseURL: "/api",
+})
+
+// Authenticate if we are logged in
+api.interceptors.request.use((config) => {
+ // Fetch the access token
+ const access_token: string | null = getAccessToken()
+
+ // Add the Authorization header if a token is available
+ if (access_token) {
+ config.headers.Authorization = `Bearer ${access_token}`
+ }
+
+ return config
+})
+
+// Log out the user if a request has been unauthenticated
+api.interceptors.response.use(
+ (response) => response,
+ (error) => {
+ if (error.response?.status === 401) {
+ const auth = useAuthStore()
+ auth.logout()
+
+ // XXX Should we go back to the log in page?
+ // router.push("/login")
+ }
+
+ return Promise.reject(error)
+ }
+)
+
+// Export the API
+export default api
+import api from "@/api"
import type { Mirror } from "@/types/Mirror";
+// Fetch all mirrors
export async function fetchMirrors(): Promise<Mirror[]> {
- // Fetch all mirrors
- const response = await fetch("/api/v1/mirrors");
- if (!response.ok)
- throw new Error("Failed to fetch mirrors");
-
- return response.json();
+ try {
+ const response = await api.get("/v1/mirrors");
+ return response.data;
+ } catch (error) {
+ throw new Error("Failed to load mirrors");
+ }
}
+++ /dev/null
-import { isTokenExpired } from './jwt'
-
-interface RefreshResponse {
- access_token: string;
- refresh_token?: string;
-}
-
-async function refreshToken(): Promise<boolean> {
- try {
- const response = await fetch("/api/v1/auth/refresh", {
- method: "POST",
- credentials: "include",
- });
- if (!response.ok)
- return false;
-
- // Parse the response
- const data: RefreshResponse = await response.json();
-
- // Store the new access token
- localStorage.setItem("token", data.access_token);
-
- return true;
-
- } catch {
- return false;
- }
-}
-
-export async function fetchWithAuth(input: RequestInfo, init?: RequestInit): Promise<Response> {
- let token = localStorage.getItem("token");
-
- if (!token || isTokenExpired(token)) {
- const refreshed = await refreshToken();
- if (!refreshed) {
- // no valid token and refresh failed — maybe logout user here or throw
- throw new Error('Not authenticated');
- }
-
- // Check if we have received a token
- token = localStorage.getItem("token");
- if (!token)
- throw new Error('No access token after refresh');
- }
-
- const authHeaders = {
- ...(init?.headers || {}),
- Authorization: `Bearer ${token}`,
- };
-
- const fetchInit = {
- ...init,
- headers: authHeaders,
- };
-
- return fetch(input, fetchInit);
-}