67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
import "server-only";
|
|
import { logApiRequest, logApiResponse } from "@/lib/api/dev-logger";
|
|
|
|
const ACCOUNTS_BASE_URL = process.env.GOOYAL_ACCOUNTS_BASE_URL!;
|
|
const CLIENT_ID = process.env.GOOYAL_CLIENT_ID!;
|
|
const CLIENT_SECRET = process.env.GOOYAL_CLIENT_SECRET!;
|
|
|
|
function basicAuthHeader() {
|
|
return "Basic " + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64");
|
|
}
|
|
|
|
const ERROR_MESSAGES_FA: Record<string, string> = {
|
|
invalid_grant: "کد تایید نامعتبر یا منقضی شده است.",
|
|
invalid_client: "خطا در پیکربندی سرویس احراز هویت. لطفاً بعداً تلاش کنید.",
|
|
invalid_request: "درخواست نامعتبر است.",
|
|
unsupported_grant_type: "خطا در پیکربندی سرویس احراز هویت.",
|
|
};
|
|
|
|
export class GooyalAuthError extends Error {
|
|
constructor(
|
|
public status: number,
|
|
public code: string,
|
|
description?: string,
|
|
) {
|
|
super(ERROR_MESSAGES_FA[code] ?? description ?? code);
|
|
}
|
|
}
|
|
|
|
export interface GooyalTokenResponse {
|
|
access_token: string;
|
|
refresh_token?: string;
|
|
token_type: string;
|
|
expires_in: number;
|
|
scope: string;
|
|
}
|
|
|
|
export async function refreshAccessToken(refreshToken: string): Promise<GooyalTokenResponse> {
|
|
const url = `${ACCOUNTS_BASE_URL}/oauth2/token/`;
|
|
const body = new URLSearchParams({
|
|
grant_type: "refresh_token",
|
|
refresh_token: refreshToken,
|
|
});
|
|
|
|
// Never print real tokens to the terminal — log the request shape, not the secret values.
|
|
logApiRequest("gooyal", "POST", url, { grant_type: "refresh_token", refresh_token: "<redacted>" });
|
|
|
|
const res = await fetch(url, {
|
|
method: "POST",
|
|
headers: {
|
|
Authorization: basicAuthHeader(),
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
body: body.toString(),
|
|
cache: "no-store",
|
|
});
|
|
const data = await res.json().catch(() => ({}));
|
|
logApiResponse("gooyal", "POST", url, res.status, {
|
|
...data,
|
|
access_token: data.access_token ? "<redacted>" : undefined,
|
|
refresh_token: data.refresh_token ? "<redacted>" : undefined,
|
|
});
|
|
|
|
if (!res.ok) {
|
|
throw new GooyalAuthError(res.status, data.error ?? "refresh_failed", data.error_description);
|
|
}
|
|
return data;
|
|
}
|