Retry authorized Directus registration credentials

This commit is contained in:
makearmy 2026-07-10 11:13:18 -04:00
parent 92ce8bce97
commit 4884b5d367

View file

@ -10,18 +10,21 @@ const BASE = (
"" ""
).replace(/\/$/, ""); ).replace(/\/$/, "");
// DIRECTUS_TOKEN_ADMIN_REGISTER is the canonical credential for the production // DIRECTUS_TOKEN_ADMIN_REGISTER is the canonical credential for the production
// Registration Bot policy. Keep the older aliases as fallbacks so an existing // Registration Bot policy. Keep older aliases as independently tested fallbacks:
// deployment does not silently lose authentication during migration. // a configured but stale token must not hide a later valid credential.
const TOKEN_ADMIN_REGISTER = const REGISTRATION_CREDENTIALS = [
process.env.DIRECTUS_TOKEN_ADMIN_REGISTER || ["DIRECTUS_TOKEN_ADMIN_REGISTER", process.env.DIRECTUS_TOKEN_ADMIN_REGISTER],
process.env.DIRECTUS_SERVICE_TOKEN || ["DIRECTUS_SERVICE_TOKEN", process.env.DIRECTUS_SERVICE_TOKEN],
process.env.DIRECTUS_ADMIN_TOKEN || ["DIRECTUS_ADMIN_TOKEN", process.env.DIRECTUS_ADMIN_TOKEN],
""; // server-only ].filter(
(entry, index, entries): entry is [string, string] =>
Boolean(entry[1]) && entries.findIndex((other) => other[1] === entry[1]) === index
);
const ROLE_MEMBER_NAME = process.env.DIRECTUS_ROLE_MEMBER_NAME || "Users"; const ROLE_MEMBER_NAME = process.env.DIRECTUS_ROLE_MEMBER_NAME || "Users";
const PROJECTS_COLLECTION = process.env.DIRECTUS_PROJECTS_COLLECTION || "projects"; const PROJECTS_COLLECTION = process.env.DIRECTUS_PROJECTS_COLLECTION || "projects";
if (!BASE) console.warn("[directus] Missing DIRECTUS_URL / NEXT_PUBLIC_API_BASE_URL"); if (!BASE) console.warn("[directus] Missing DIRECTUS_URL / NEXT_PUBLIC_API_BASE_URL");
if (!TOKEN_ADMIN_REGISTER) if (!REGISTRATION_CREDENTIALS.length)
console.warn( console.warn(
"[directus] Missing DIRECTUS_TOKEN_ADMIN_REGISTER (or legacy service-token alias) " + "[directus] Missing DIRECTUS_TOKEN_ADMIN_REGISTER (or legacy service-token alias) " +
"used for registration and username login" "used for registration and username login"
@ -134,17 +137,33 @@ export async function dxDELETE<T = any>(path: string, bearer: string): Promise<T
export async function directusAdminFetch<T = any>(path: string, init?: RequestInit): Promise<T> { export async function directusAdminFetch<T = any>(path: string, init?: RequestInit): Promise<T> {
if (!BASE) throw new Error("Missing Directus base URL"); if (!BASE) throw new Error("Missing Directus base URL");
if (!TOKEN_ADMIN_REGISTER) throw new Error("Missing Directus registration credential"); if (!REGISTRATION_CREDENTIALS.length) throw new Error("Missing Directus registration credential");
const res = await fetch(`${BASE}${path}`, {
...init, let lastAuthorizationError: any = null;
headers: { for (const [credentialName, credential] of REGISTRATION_CREDENTIALS) {
Accept: "application/json", const res = await fetch(`${BASE}${path}`, {
Authorization: `Bearer ${TOKEN_ADMIN_REGISTER}`, ...init,
...(init?.headers || {}), headers: {
}, Accept: "application/json",
cache: "no-store", Authorization: `Bearer ${credential}`,
}); ...(init?.headers || {}),
return (await throwIfNotOk(res)) as T; },
cache: "no-store",
});
try {
return (await throwIfNotOk(res)) as T;
} catch (error: any) {
if (error?.status !== 401 && error?.status !== 403) throw error;
lastAuthorizationError = error;
console.warn(`[directus] Registration credential rejected: ${credentialName}`, {
status: error.status,
code: error?.detail?.errors?.[0]?.extensions?.code,
});
}
}
throw lastAuthorizationError ?? new Error("No authorized Directus registration credential");
} }
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────