89 lines
2.4 KiB
TypeScript
89 lines
2.4 KiB
TypeScript
import { NextResponse, type NextRequest } from "next/server";
|
|
|
|
import { AUTH_VALIDATE_URL, DEFAULT_COOKIE_NAMES } from "./constants";
|
|
import type { SfAuthCookieNames } from "./middleware";
|
|
|
|
export type SfAuthCallbackOptions = {
|
|
redirectTo: string;
|
|
cookieNames?: SfAuthCookieNames;
|
|
validateEndpoint?: string;
|
|
};
|
|
|
|
type ValidateResponse = {
|
|
valid: boolean;
|
|
user_id: string;
|
|
};
|
|
|
|
const resolveCookieNames = (cookieNames?: SfAuthCookieNames) => ({
|
|
userId: cookieNames?.userId ?? DEFAULT_COOKIE_NAMES.userId,
|
|
username: cookieNames?.username ?? DEFAULT_COOKIE_NAMES.username
|
|
});
|
|
|
|
const errorResponse = (message: string, status = 400) =>
|
|
new NextResponse(message, {
|
|
status,
|
|
headers: {
|
|
"content-type": "text/plain; charset=utf-8"
|
|
}
|
|
});
|
|
|
|
export const createSfAuthCallbackRoute = (
|
|
options: SfAuthCallbackOptions
|
|
) => {
|
|
const cookieNames = resolveCookieNames(options.cookieNames);
|
|
const validateUrl = options.validateEndpoint ?? AUTH_VALIDATE_URL;
|
|
|
|
return async (request: NextRequest) => {
|
|
const url = new URL(request.url);
|
|
const userId = url.searchParams.get("user_id");
|
|
const username = url.searchParams.get("username");
|
|
const key = url.searchParams.get("key");
|
|
|
|
if (!userId || !username || !key) {
|
|
return errorResponse("Missing required query parameters.");
|
|
}
|
|
|
|
let validateResponse: ValidateResponse;
|
|
|
|
try {
|
|
const response = await fetch(validateUrl, {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json"
|
|
},
|
|
body: JSON.stringify({ user_id: userId, key })
|
|
});
|
|
|
|
if (!response.ok) {
|
|
return errorResponse("Failed to validate credentials.");
|
|
}
|
|
|
|
validateResponse = (await response.json()) as ValidateResponse;
|
|
} catch (error) {
|
|
return errorResponse("Unable to validate credentials.", 500);
|
|
}
|
|
|
|
if (!validateResponse.valid || validateResponse.user_id !== userId) {
|
|
return errorResponse("Invalid credentials.");
|
|
}
|
|
|
|
const redirectTarget = new URL(options.redirectTo, request.url);
|
|
const response = NextResponse.redirect(redirectTarget);
|
|
|
|
response.cookies.set(cookieNames.userId, userId, {
|
|
httpOnly: true,
|
|
sameSite: "strict",
|
|
secure: true,
|
|
path: "/"
|
|
});
|
|
|
|
response.cookies.set(cookieNames.username, username, {
|
|
httpOnly: true,
|
|
sameSite: "strict",
|
|
secure: true,
|
|
path: "/"
|
|
});
|
|
|
|
return response;
|
|
};
|
|
};
|