diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index aef7a3b6ca..ae5c6c6ec1 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -44,7 +44,6 @@ import { isClientError, } from "./errors.js" import { AuthInternal, raw, skipCSRFCheck } from "./lib/index.js" -import { setEnvDefaults, createActionURL } from "./lib/utils/env.js" import renderPage from "./lib/pages/index.js" import { setLogger, type LoggerInstance } from "./lib/utils/logger.js" import { toInternalRequest, toResponse } from "./lib/utils/web.js" @@ -68,7 +67,14 @@ import { JWT, JWTOptions } from "./jwt.js" import { isAuthAction } from "./lib/utils/actions.js" export { customFetch } from "./lib/symbols.js" -export { skipCSRFCheck, raw, setEnvDefaults, createActionURL, isAuthAction } +export { + setEnvDefaults, + collectEnvSecrets, + applyEnvSecrets, + applyEnvSettings, + createActionURL, +} from "./lib/utils/env.js" +export { skipCSRFCheck, raw, isAuthAction } export async function Auth( request: Request, diff --git a/packages/core/src/lib/utils/env.ts b/packages/core/src/lib/utils/env.ts index afe05444b5..634d900320 100644 --- a/packages/core/src/lib/utils/env.ts +++ b/packages/core/src/lib/utils/env.ts @@ -1,12 +1,80 @@ import type { AuthAction } from "../../types.js" import type { AuthConfig } from "../../index.js" import { setLogger } from "./logger.js" +import type { Provider } from "../../providers/index.js" -/** - * Set default env variables on the config object - * @param suppressWarnings intended for framework authors. - */ -export function setEnvDefaults( +export type ProviderSecrets = { + provider: Provider + providerId: string + PROVIDER_ID: string + clientId?: T + clientSecret?: T + issuer?: T + apiKey?: T +} + +export type EnvSecrets = { + secrets: T[] + providers: ProviderSecrets[] +} + +export function collectEnvSecrets( + envObject: any, + config: AuthConfig +): EnvSecrets { + const secrets = [] + if (config.secret) { + secrets.push(...config.secret) + } + if (envObject.AUTH_SECRET) { + secrets.push(envObject.AUTH_SECRET) + } + for (const i of [1, 2, 3]) { + const secret = envObject[`AUTH_SECRET_${i}`] + if (secret) { + secrets.push(secret) + } + } + + const providers = config.providers.map((provider) => { + const { id } = typeof provider === "function" ? provider({}) : provider + const ID = id.toUpperCase().replace(/-/g, "_") + const secrets = { + clientId: envObject[`AUTH_${ID}_ID`], + clientSecret: envObject[`AUTH_${ID}_SECRET`], + issuer: envObject[`AUTH_${ID}_ISSUER`], + apiKey: envObject[`AUTH_${ID}_KEY`], + } + + /** + * Attach provider and id metadata to the secrets object. + * Make non-enumerable to simplify iteration over secrets. + */ + Object.defineProperties(secrets, { + provider: { + value: provider, + enumerable: false, + }, + providerId: { + value: id, + enumerable: false, + }, + PROVIDER_ID: { + value: ID, + enumerable: false, + }, + }) + + return secrets as ProviderSecrets + }) + + return { + secrets, + providers, + } +} + +export function applyEnvSettings( envObject: any, config: AuthConfig, suppressBasePathWarning = false @@ -30,16 +98,6 @@ export function setEnvDefaults( config.basePath ??= `/auth` } - if (!config.secret?.length) { - config.secret = [] - const secret = envObject.AUTH_SECRET - if (secret) config.secret.push(secret) - for (const i of [1, 2, 3]) { - const secret = envObject[`AUTH_SECRET_${i}`] - if (secret) config.secret.unshift(secret) - } - } - config.redirectProxyUrl ??= envObject.AUTH_REDIRECT_PROXY_URL config.trustHost ??= !!( envObject.AUTH_URL ?? @@ -48,26 +106,39 @@ export function setEnvDefaults( envObject.CF_PAGES ?? envObject.NODE_ENV !== "production" ) - config.providers = config.providers.map((provider) => { - const { id } = typeof provider === "function" ? provider({}) : provider - const ID = id.toUpperCase().replace(/-/g, "_") - const clientId = envObject[`AUTH_${ID}_ID`] - const clientSecret = envObject[`AUTH_${ID}_SECRET`] - const issuer = envObject[`AUTH_${ID}_ISSUER`] - const apiKey = envObject[`AUTH_${ID}_KEY`] - const finalProvider = - typeof provider === "function" - ? provider({ clientId, clientSecret, issuer, apiKey }) - : provider - if (finalProvider.type === "oauth" || finalProvider.type === "oidc") { - finalProvider.clientId ??= clientId - finalProvider.clientSecret ??= clientSecret - finalProvider.issuer ??= issuer - } else if (finalProvider.type === "email") { - finalProvider.apiKey ??= apiKey +} + +export function applyEnvSecrets(config: AuthConfig, secrets: EnvSecrets) { + config.secret = secrets.secrets + config.providers = secrets.providers.map( + ({ provider, clientId, clientSecret, issuer, apiKey }) => { + const finalProvider = + typeof provider === "function" + ? provider({ clientId, clientSecret, issuer, apiKey }) + : provider + if (finalProvider.type === "oauth" || finalProvider.type === "oidc") { + finalProvider.clientId ??= clientId + finalProvider.clientSecret ??= clientSecret + finalProvider.issuer ??= issuer + } else if (finalProvider.type === "email") { + finalProvider.apiKey ??= apiKey + } + return finalProvider } - return finalProvider - }) + ) +} + +/** + * Set default env variables on the config object + * @param suppressWarnings intended for framework authors. + */ +export function setEnvDefaults( + envObject: any, + config: AuthConfig, + suppressBasePathWarning = false +) { + applyEnvSettings(envObject, config, suppressBasePathWarning) + applyEnvSecrets(config, collectEnvSecrets(envObject, config)) } export function createActionURL(