@auth0/nextjs-auth0
Version:
Auth0 Next.js SDK
152 lines (151 loc) • 4.98 kB
JavaScript
import { NextResponse } from "next/server.js";
import { MfaVerifyError } from "../errors/mfa-errors.js";
import { GRANT_TYPE_MFA_OOB, GRANT_TYPE_MFA_OTP, GRANT_TYPE_MFA_RECOVERY_CODE } from "../types/mfa.js";
/**
* Transforms Auth0 API authenticator response (snake_case) to SDK format (camelCase).
*
* @param auth - Raw authenticator from Auth0 API
* @returns Transformed authenticator
*/
export function camelizeAuthenticator(auth) {
return {
id: auth.id,
authenticatorType: auth.authenticator_type,
type: auth.type,
active: auth.active,
name: auth.name,
phoneNumber: auth.phone_number,
oobChannel: auth.oob_channel,
createdAt: auth.created_at,
lastAuthenticatedAt: auth.last_auth
};
}
/**
* Transforms Auth0 API challenge response (snake_case) to SDK format (camelCase).
*
* @param result - Raw challenge result from Auth0 API
* @returns Transformed challenge response
*/
export function camelizeChallengeResponse(result) {
return {
challengeType: result.challenge_type,
oobCode: result.oob_code,
bindingMethod: result.binding_method
};
}
/**
* Transforms Auth0 API enrollment response (snake_case) to SDK format (camelCase).
* Builds discriminated union based on authenticator type.
*
* @param result - Raw enrollment result from Auth0 API
* @returns Transformed enrollment response
*/
export function buildEnrollmentResponse(result) {
const baseResponse = {
authenticatorType: result.authenticator_type,
id: result.id,
recoveryCodes: result.recovery_codes
};
if (result.authenticator_type === "otp") {
const response = {
...baseResponse,
authenticatorType: "otp",
secret: result.secret,
barcodeUri: result.barcode_uri
};
return response;
}
else if (result.authenticator_type === "oob") {
return {
...baseResponse,
authenticatorType: "oob",
oobChannel: result.oob_channel,
name: result.name,
oobCode: result.oob_code,
bindingMethod: result.binding_method,
barcodeUri: result.barcode_uri
};
}
throw new Error(`Unknown authenticator type: ${result.authenticator_type}`);
}
/**
* Builds type-safe enrollment options from request body.
* Validates type-specific required fields.
*
* @param body - Request body
* @param authenticatorType - Type of authenticator to enroll
* @returns Tuple of [options, null] or [null, errorResponse]
*/
export function buildEnrollOptions(body, authenticatorType) {
const bodyObj = body;
if (authenticatorType === "oob") {
if (!bodyObj.oobChannels || !Array.isArray(bodyObj.oobChannels)) {
return [
null,
NextResponse.json({
error: "invalid_request",
error_description: "Missing or invalid oobChannels for OOB enrollment"
}, { status: 400 })
];
}
const phoneNumber = typeof bodyObj.phoneNumber === "string" && bodyObj.phoneNumber !== ""
? bodyObj.phoneNumber
: undefined;
const email = typeof bodyObj.email === "string" && bodyObj.email !== ""
? bodyObj.email
: undefined;
return [
{
authenticatorTypes: ["oob"],
oobChannels: bodyObj.oobChannels,
phoneNumber,
email
},
null
];
}
else {
// otp
return [
{
authenticatorTypes: ["otp"]
},
null
];
}
}
export const buildVerifyParams = (options, mfaToken) => {
const params = new URLSearchParams();
params.append("mfa_token", mfaToken);
if ("otp" in options && options.otp) {
params.append("otp", options.otp);
}
else if ("oobCode" in options &&
"bindingCode" in options &&
options.oobCode &&
options.bindingCode) {
params.append("oob_code", options.oobCode);
params.append("binding_code", options.bindingCode);
}
else if ("recoveryCode" in options && options.recoveryCode) {
params.append("recovery_code", options.recoveryCode);
}
else {
throw new MfaVerifyError("invalid_request", "At least one verification credential required (otp, oobCode+bindingCode, or recoveryCode)");
}
return params;
};
export const getVerifyGrantType = (params) => {
if (params.has("otp")) {
return GRANT_TYPE_MFA_OTP;
}
else if (params.has("oob_code") && params.has("binding_code")) {
return GRANT_TYPE_MFA_OOB;
}
else if (params.has("recovery_code")) {
return GRANT_TYPE_MFA_RECOVERY_CODE;
}
else {
throw new MfaVerifyError("invalid_request", "No verification credential provided");
}
};