mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-21 04:39:06 +00:00
401 reauth experiments
This commit is contained in:
@@ -11,6 +11,9 @@ import {
|
||||
import createFetchClient from "openapi-react-query";
|
||||
import { assertExistsAndNonEmptyString } from "./utils";
|
||||
import { isBuildPhase } from "./next";
|
||||
import { Session } from "next-auth";
|
||||
import { assertCustomSession } from "./types";
|
||||
import { HttpMethod, PathsWithMethod } from "openapi-typescript-helpers";
|
||||
|
||||
const API_URL = !isBuildPhase
|
||||
? assertExistsAndNonEmptyString(process.env.NEXT_PUBLIC_API_URL)
|
||||
@@ -25,12 +28,20 @@ export const client = createClient<paths>({
|
||||
export const $api = createFetchClient<paths>(client);
|
||||
|
||||
let currentAuthToken: string | null | undefined = null;
|
||||
let refreshAuthCallback: (() => Promise<Session | null>) | null = null;
|
||||
|
||||
const injectAuth = (request: Request, accessToken: string | null) => {
|
||||
if (accessToken) {
|
||||
request.headers.set("Authorization", `Bearer ${currentAuthToken}`);
|
||||
} else {
|
||||
request.headers.delete("Authorization");
|
||||
}
|
||||
return request;
|
||||
};
|
||||
|
||||
client.use({
|
||||
onRequest({ request }) {
|
||||
if (currentAuthToken) {
|
||||
request.headers.set("Authorization", `Bearer ${currentAuthToken}`);
|
||||
}
|
||||
request = injectAuth(request, currentAuthToken || null);
|
||||
// XXX Only set Content-Type if not already set (FormData will set its own boundary)
|
||||
// This is a work around for uploading file, we're passing a formdata
|
||||
// but the content type was still application/json
|
||||
@@ -44,7 +55,46 @@ client.use({
|
||||
},
|
||||
});
|
||||
|
||||
client.use({
|
||||
async onResponse({ response, request, params, schemaPath }) {
|
||||
if (response.status === 401) {
|
||||
console.log(
|
||||
"response.status is 401!",
|
||||
refreshAuthCallback,
|
||||
request,
|
||||
schemaPath,
|
||||
);
|
||||
}
|
||||
if (response.status === 401 && refreshAuthCallback) {
|
||||
try {
|
||||
const session = await refreshAuthCallback();
|
||||
if (!session) {
|
||||
console.warn("Token refresh failed, no session returned");
|
||||
return response;
|
||||
}
|
||||
const customSession = assertCustomSession(session);
|
||||
currentAuthToken = customSession.accessToken;
|
||||
const r = await client.request(
|
||||
request.method as HttpMethod,
|
||||
schemaPath as PathsWithMethod<paths, HttpMethod>,
|
||||
...params,
|
||||
);
|
||||
return r.response;
|
||||
} catch (error) {
|
||||
console.error("Token refresh failed during 401 retry:", error);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
},
|
||||
});
|
||||
|
||||
// the function contract: lightweight, idempotent
|
||||
export const configureApiAuth = (token: string | null | undefined) => {
|
||||
currentAuthToken = token;
|
||||
};
|
||||
|
||||
export const configureApiAuthRefresh = (
|
||||
callback: (() => Promise<Session | null>) | null,
|
||||
) => {
|
||||
refreshAuthCallback = callback;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user