From 5a4b8e0ca1780023364f1ec1dd527876535ffbad Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Mon, 27 Apr 2026 22:13:42 -0500 Subject: [PATCH 1/5] feat(core): support PEM-encoded keys in environment variables --- packages/core/src/@types/session.ts | 17 ++++ packages/core/src/jose.ts | 72 +++++++++++++--- packages/core/src/shared/assert.ts | 15 ++++ packages/core/test/env.test.ts | 23 +++++ packages/core/test/jose.test.ts | 127 ++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 12 deletions(-) diff --git a/packages/core/src/@types/session.ts b/packages/core/src/@types/session.ts index 949a740..0b99d82 100644 --- a/packages/core/src/@types/session.ts +++ b/packages/core/src/@types/session.ts @@ -22,12 +22,18 @@ export interface CryptoSecret { encrypt: CryptoKey | CryptoKeyPair } +export interface AsymmetricKeyPairFromEnv { + publicKey: string + privateKey: string +} + /** * A symmetric secret or asymmetric key pair used for JWT operations. * * - string / Uint8Array: used as-is for HMAC (signed) or AES (encrypted) * - CryptoKey: Web Crypto API key, for environments that support it * - CryptoKeyPair: asymmetric signing/encryption (RS256, ES256, EdDSA, RSA-OAEP, etc.) + * - AsymmetricKeyPairFromEnv: asymmetric key pair formatted as PEM strings */ export type SecretKey = string | Uint8Array | CryptoKey | CryptoKeyPair | CryptoSecret @@ -133,6 +139,17 @@ export type JWTConfig = { * Policy for renewing or capping token lifetime (pairs with `maxExpiration` where applicable). */ expirationStrategy?: JWTExpirationStrategy + /** + * Optional algorithm override for key import when using PEM-formatted keys from environment variables. + * + * > Currently only supported for `signed` and `encrypted` JWT modes and not for `sealed` mode. + * + * @todo Add `AURA_AUTH_SIGNING_PUBLIC|PRIVATE_KEY` and `AURA_AUTH_ENCRYPTION_PUBLIC|PRIVATE_KEY` env var + * support for separate signing/encryption keys in sealed mode, which would also require supporting separate + * algorithm overrides for each key (e.g. `AURA_AUTH_SIGNING_ALGORITHM` and `AURA_AUTH_ENCRYPTION_ALGORITHM`). + * @default "RS256" + */ + importedAlgorithm?: JWTSigningAlgorithm | JWTKeyAlgorithm } & JWTConfigBase /** diff --git a/packages/core/src/jose.ts b/packages/core/src/jose.ts index d4d60e4..0d1070d 100644 --- a/packages/core/src/jose.ts +++ b/packages/core/src/jose.ts @@ -15,9 +15,25 @@ import { } from "@aura-stack/jose" export { base64url, type JWTPayload } from "@aura-stack/jose/jose" import { AuthInternalError, AuthSecurityError } from "@/shared/errors.ts" -import { isCryptoKey, isCryptoKeyPair, isCryptoSecret, isEncryptedMode, isSealedMode, isSignedMode } from "@/shared/assert.ts" +import { + isCryptoKey, + isCryptoKeyPair, + isCryptoSecret, + isEncryptedMode, + isPemFormattedKeyPairFromEnv, + isSealedMode, + isSignedMode, +} from "@/shared/assert.ts" export { encoder, getRandomBytes, getSubtleCrypto } from "@aura-stack/jose/crypto" -import type { User, SessionConfig, JWTKey } from "@/@types/index.ts" +import type { + User, + SessionConfig, + JWTKey, + AsymmetricKeyPairFromEnv, + JWTSigningAlgorithm, + JWTKeyAlgorithm, +} from "@/@types/index.ts" +import { importPKCS8, importSPKI } from "@aura-stack/jose/jose" const getJWTConfig = (config?: SessionConfig) => { return config?.jwt @@ -102,7 +118,32 @@ export const verifyMaxExpiration = (payload: TypedJWTPayload>) => } } -const getSecrets = async (secret: JWTKey, salt: string) => { +const getSecrets = async ( + secret: JWTKey | AsymmetricKeyPairFromEnv, + salt: string, + importedAlgorithm?: JWTSigningAlgorithm | JWTKeyAlgorithm +) => { + if (isPemFormattedKeyPairFromEnv(secret)) { + const { publicKey, privateKey } = secret + const algorithm = getEnv("ALGORITHM") ?? getEnv("ALG") ?? importedAlgorithm ?? "RS256" + const importedPrivateKey = await importPKCS8(privateKey, algorithm, { extractable: true }) + const importedPublicKey = await importSPKI(publicKey, algorithm, { extractable: true }) + return { + jwsSecret: { + publicKey: importedPublicKey, + privateKey: importedPrivateKey, + }, + jweSecret: { + publicKey: importedPublicKey, + privateKey: importedPrivateKey, + }, + jwtSecret: { + sign: importedPrivateKey, + encrypt: importedPublicKey, + }, + } + } + if (isCryptoSecret(secret)) { return { jwsSecret: secret.sign, @@ -138,6 +179,20 @@ const getSecrets = async (secret: JWTKey, salt: string) => { } } +const getSecretKey = (secret?: JWTKey) => { + secret ??= getEnv("SECRET") + if (secret) return secret + const publicKey = getEnv("PUBLIC_KEY") + const privateKey = getEnv("PRIVATE_KEY") + if (publicKey && privateKey) { + return { publicKey, privateKey } + } + throw new AuthInternalError( + "JOSE_INITIALIZATION_FAILED", + "AURA_AUTH_SECRET environment variable is not set and no secret was provided." + ) +} + /** * Creates the JOSE instance used for signing and verifying tokens. It derives keys * for session tokens and CSRF tokens. For security and determinism, it's required @@ -153,14 +208,7 @@ const getSecrets = async (secret: JWTKey, salt: string) => { * @returns jose instance with methods for encoding/decoding JWTs and signing/verifying JWSs */ export const createJoseInstance = (secret?: JWTKey, session?: SessionConfig) => { - secret ??= getEnv("SECRET") - if (!secret) { - throw new AuthInternalError( - "JOSE_INITIALIZATION_FAILED", - "AURA_AUTH_SECRET environment variable is not set and no secret was provided." - ) - } - + const secretKey = getSecretKey(secret) const salt = getEnv("SALT") if (!salt) { throw new AuthInternalError( @@ -179,7 +227,7 @@ export const createJoseInstance = (secret?: JWT } const jose = (async () => { - const { jwsSecret, jweSecret, jwtSecret } = await getSecrets(secret, salt) + const { jwsSecret, jweSecret, jwtSecret } = await getSecrets(secretKey, salt, session?.jwt?.importedAlgorithm) return { jwt: createJWT(jwtSecret), diff --git a/packages/core/src/shared/assert.ts b/packages/core/src/shared/assert.ts index 3da8900..502366c 100644 --- a/packages/core/src/shared/assert.ts +++ b/packages/core/src/shared/assert.ts @@ -128,3 +128,18 @@ export const isCryptoSecret = (value: unknown): value is CryptoSecret => { (isCryptoKey(value.encrypt) || isCryptoKeyPair(value.encrypt)) ) } + +export const isPemFormattedKey = (value: unknown): value is string => { + return typeof value === "string" && /-----BEGIN (PUBLIC|PRIVATE) KEY-----/.test(value) +} + +export const isPemFormattedKeyPairFromEnv = (value: unknown): value is { publicKey: string; privateKey: string } => { + return ( + typeof value === "object" && + value !== null && + "publicKey" in value && + "privateKey" in value && + isPemFormattedKey(value.publicKey) && + isPemFormattedKey(value.privateKey) + ) +} diff --git a/packages/core/test/env.test.ts b/packages/core/test/env.test.ts index ce5e3c0..0f3d613 100644 --- a/packages/core/test/env.test.ts +++ b/packages/core/test/env.test.ts @@ -1,6 +1,7 @@ import { afterEach, describe, expect, test, vi } from "vitest" import { env } from "@/shared/env.ts" import { createSecretValue } from "@/shared/crypto.ts" +import { exportPKCS8, exportSPKI, generateKeyPair } from "@aura-stack/jose/jose" describe("env", () => { afterEach(() => { @@ -27,4 +28,26 @@ describe("env", () => { vi.stubEnv("AURA_AUTH_SECRET", secret2) expect(env.AURA_AUTH_SECRET).toBe(secret2) }) + + test("direct PEM formatted RSA keys", async () => { + const pem = `-----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtGbid5pLu9wsGut7Fg26 + SPBGntzZk6i17MIf2eS++01/7uq0a59yxYa1AvPbO9OdQDngRup7zPUc7dKivwQe + hHTPQ86H9EJkgKqupKj8PUbfzSFzpwcTs9RZmd9o9jBXOkbtH18Pn+jNbqxB0AFA + C4ZYfU+l2981U4Xb5UAOfJaqbEWlG0AvW8dqkU1TtAoXtGpoINv46qHF1gSYRDsU + AafJaMzLOOC0EhP3U/XZNuAFqgOosGx5iJ1+fyFwMjH+w5iSAXvk1C7KyPTYJDMV + JyuDj7yG/TR5yDPS7fyFsbdrLQlwCPqUCmg8Y9lQltXYWu8PptxJYZV4RBbBJ8fr + PQIDAQAB + -----END PUBLIC KEY-----` + vi.stubEnv("AURA_AUTH_SECRET", pem) + expect(env.AURA_AUTH_SECRET).toBe(pem) + }) + + test("PEM formatted RSA keys with newlines", async () => { + const keyPair = await generateKeyPair("RS256", { extractable: true }) + const publicKeyPEM = await exportSPKI(keyPair.publicKey) + const privateKeyPEM = await exportPKCS8(keyPair.privateKey) + vi.stubEnv("AURA_AUTH_SECRET", `${publicKeyPEM}\n${privateKeyPEM}`) + expect(env.AURA_AUTH_SECRET).toBe(`${publicKeyPEM}\n${privateKeyPEM}`) + }) }) diff --git a/packages/core/test/jose.test.ts b/packages/core/test/jose.test.ts index 5ecf07b..96700ad 100644 --- a/packages/core/test/jose.test.ts +++ b/packages/core/test/jose.test.ts @@ -539,4 +539,131 @@ describe("createJoseInstance", () => { expect(decoded).toMatchObject(payload) }) }) + + test("PEM formatted RSA keys", async () => { + vi.stubEnv("AURA_AUTH_SALT", createSecretValue(32)) + + const publicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5eSIl71g3dyLEFYbv3B +i93M9nCBLWkbI8mOQLmGgXEj3k92rwfF/+B5gCr1OMUmV+aSLsDvdhDiljQAUpQO +3ziLaYlk0k8paw7fZjkIejz5BwiWFODTqg9HWSOGr5hfJzyL9gvzaAI2Sp7htei/ +En0u79eRNQNII0dmQtwiMpIEQbisadUEp5+s0Dd7yGUoR18V7pv2A/Ohii8lMUUL +Efs71Ypf0L5rO9SAhjztxhR6wGWYe+uCNDEF0wuQ/ZL9TvI46Zpf+Z1z+0CzpXYr +Eloe8oqcCuPIJ1GszZst+qkgFdyo0BXGa1nuA/21ZLmAwUXdzmF1nsGg0J/sUcEQ +TwIDAQAB +-----END PUBLIC KEY-----` + const privateKey = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/l5IiXvWDd3Is +QVhu/cGL3cz2cIEtaRsjyY5AuYaBcSPeT3avB8X/4HmAKvU4xSZX5pIuwO92EOKW +NABSlA7fOItpiWTSTylrDt9mOQh6PPkHCJYU4NOqD0dZI4avmF8nPIv2C/NoAjZK +nuG16L8SfS7v15E1A0gjR2ZC3CIykgRBuKxp1QSnn6zQN3vIZShHXxXum/YD86GK +LyUxRQsR+zvVil/Qvms71ICGPO3GFHrAZZh764I0MQXTC5D9kv1O8jjpml/5nXP7 +QLOldisSWh7yipwK48gnUazNmy36qSAV3KjQFcZrWe4D/bVkuYDBRd3OYXWewaDQ +n+xRwRBPAgMBAAECggEACh2r77IMck7cUbDexSsTZo0LlUsWzvmya9ib10s60MFs +1hnJyu91CVyy6maaQJwyn5TpgAJCdbBQWANSRwnq1RqZTDVSBCnkDNm7eukk/otG +NmEolENteZh8uTY/SZMygJHzIK0iqQm0D/GR0+oZ+JU9seUzlTuuOeQ7TOluY5wR +i/V6ldrDSOxd2xIKUnxemw0qwbUz0oZ5CKo22K+VksGwa/PempkpyZloSGsE+QR5 +5cZwWxGelzUCDyflOImX+TCKI4IsuBOI+CaQohY3j3xSEunSyE4BCITgtIjlHJOB +OspOYs/rYQt9xe1ZzBlRTbq/iZAonMgRS1ELm75eWQKBgQD2dlyaZIMpuhKWBWgb +tPC0CrPLxOqWi5TSkaR+kk389xOqi6m62mPph5dCxv/TrvrXD+v/uST2aAYPnLSY +3ieVF+KN5fc64M2rgUYR9kOE0ubiir1RI7L7yhYo/bmtSnpd1Wr6vJBU6zEBayTL +X4Uw+nABrO/Si5SEssb9LGF/RwKBgQDHAZ+iiOhzOJCp9kCqHYJ5ageNVT/Fc85W +40pYSAiuPlolJV43oG0EnFI7MVkvqSExHfNtk7PgQsahPTsWThJRL4stzbBINmDW +Fxl505BOoXhnJHLqnQgzmNTinnupumnENImm5ChWbujRREi6kIiZYqUlKjQjN1j1 +9TTGCto6uQKBgQCb6NA30vGuSclMIetz64iBPGv0sYL87RueAQggEYlIRzynnGYo +j9K4fk/PrHdVf9GqjqXqRUL+pVuAMM+GDLLZfByTSzCUjHVO0x5yamjX81qfYMjW +NVEaOwK9t5Pn7b9u8H0WVIaxUX7UuOSzyp9FFogYZz/m3ul68GU07whWLQKBgEhP +Mbb4MiYzpnTrUmG9qTv+p9HV6P8Q7ieqHMhpHCZb55tZsZtawmILfuGdM7/an4He +VSY6pgBVoyDRQ9f99C/lq5ewBl6my5be+9XFZsj7aOlpWAwhlOpSnP/fACYS4v10 +7ZNjkbieQiBPxHFttQSu0Dzp0dn98WgledB//v2ZAoGAFdsS7VxBMCBcJIgPoYiX +GDUYZsTiISPnSRqRk1hXkRt1woAa8CK3zsCyrruoCj3VJFk6gb+TWuyBXv4kfRkv +TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA +41a79/alPIgWSGQhEbPxR8I= +-----END PRIVATE KEY-----` + + vi.stubEnv("AURA_AUTH_PUBLIC_KEY", publicKey) + vi.stubEnv("AURA_AUTH_PRIVATE_KEY", privateKey) + const jws = createJoseInstance(undefined, { + jwt: { + mode: "signed", + signingAlgorithm: "RS256", + }, + }) + const signed = await jws.signJWS(payload) + const verified = await jws.verifyJWS(signed) + expect(verified).toMatchObject(payload) + + const jwe = createJoseInstance(undefined, { + jwt: { + mode: "encrypted", + keyAlgorithm: "RSA-OAEP-256", + encryptionAlgorithm: "A256GCM", + importedAlgorithm: "RSA-OAEP-256", + }, + }) + + const encrypted = await jwe.encryptJWE(payload) + const decrypted = await jwe.decryptJWE(encrypted) + expect(decrypted).toMatchObject(payload) + }) + + test("PEM formatted RSA keys to encode and decode JWT", async () => { + vi.stubEnv("AURA_AUTH_SALT", createSecretValue(32)) + + const publicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5eSIl71g3dyLEFYbv3B +i93M9nCBLWkbI8mOQLmGgXEj3k92rwfF/+B5gCr1OMUmV+aSLsDvdhDiljQAUpQO +3ziLaYlk0k8paw7fZjkIejz5BwiWFODTqg9HWSOGr5hfJzyL9gvzaAI2Sp7htei/ +En0u79eRNQNII0dmQtwiMpIEQbisadUEp5+s0Dd7yGUoR18V7pv2A/Ohii8lMUUL +Efs71Ypf0L5rO9SAhjztxhR6wGWYe+uCNDEF0wuQ/ZL9TvI46Zpf+Z1z+0CzpXYr +Eloe8oqcCuPIJ1GszZst+qkgFdyo0BXGa1nuA/21ZLmAwUXdzmF1nsGg0J/sUcEQ +TwIDAQAB +-----END PUBLIC KEY-----` + const privateKey = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/l5IiXvWDd3Is +QVhu/cGL3cz2cIEtaRsjyY5AuYaBcSPeT3avB8X/4HmAKvU4xSZX5pIuwO92EOKW +NABSlA7fOItpiWTSTylrDt9mOQh6PPkHCJYU4NOqD0dZI4avmF8nPIv2C/NoAjZK +nuG16L8SfS7v15E1A0gjR2ZC3CIykgRBuKxp1QSnn6zQN3vIZShHXxXum/YD86GK +LyUxRQsR+zvVil/Qvms71ICGPO3GFHrAZZh764I0MQXTC5D9kv1O8jjpml/5nXP7 +QLOldisSWh7yipwK48gnUazNmy36qSAV3KjQFcZrWe4D/bVkuYDBRd3OYXWewaDQ +n+xRwRBPAgMBAAECggEACh2r77IMck7cUbDexSsTZo0LlUsWzvmya9ib10s60MFs +1hnJyu91CVyy6maaQJwyn5TpgAJCdbBQWANSRwnq1RqZTDVSBCnkDNm7eukk/otG +NmEolENteZh8uTY/SZMygJHzIK0iqQm0D/GR0+oZ+JU9seUzlTuuOeQ7TOluY5wR +i/V6ldrDSOxd2xIKUnxemw0qwbUz0oZ5CKo22K+VksGwa/PempkpyZloSGsE+QR5 +5cZwWxGelzUCDyflOImX+TCKI4IsuBOI+CaQohY3j3xSEunSyE4BCITgtIjlHJOB +OspOYs/rYQt9xe1ZzBlRTbq/iZAonMgRS1ELm75eWQKBgQD2dlyaZIMpuhKWBWgb +tPC0CrPLxOqWi5TSkaR+kk389xOqi6m62mPph5dCxv/TrvrXD+v/uST2aAYPnLSY +3ieVF+KN5fc64M2rgUYR9kOE0ubiir1RI7L7yhYo/bmtSnpd1Wr6vJBU6zEBayTL +X4Uw+nABrO/Si5SEssb9LGF/RwKBgQDHAZ+iiOhzOJCp9kCqHYJ5ageNVT/Fc85W +40pYSAiuPlolJV43oG0EnFI7MVkvqSExHfNtk7PgQsahPTsWThJRL4stzbBINmDW +Fxl505BOoXhnJHLqnQgzmNTinnupumnENImm5ChWbujRREi6kIiZYqUlKjQjN1j1 +9TTGCto6uQKBgQCb6NA30vGuSclMIetz64iBPGv0sYL87RueAQggEYlIRzynnGYo +j9K4fk/PrHdVf9GqjqXqRUL+pVuAMM+GDLLZfByTSzCUjHVO0x5yamjX81qfYMjW +NVEaOwK9t5Pn7b9u8H0WVIaxUX7UuOSzyp9FFogYZz/m3ul68GU07whWLQKBgEhP +Mbb4MiYzpnTrUmG9qTv+p9HV6P8Q7ieqHMhpHCZb55tZsZtawmILfuGdM7/an4He +VSY6pgBVoyDRQ9f99C/lq5ewBl6my5be+9XFZsj7aOlpWAwhlOpSnP/fACYS4v10 +7ZNjkbieQiBPxHFttQSu0Dzp0dn98WgledB//v2ZAoGAFdsS7VxBMCBcJIgPoYiX +GDUYZsTiISPnSRqRk1hXkRt1woAa8CK3zsCyrruoCj3VJFk6gb+TWuyBXv4kfRkv +TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA +41a79/alPIgWSGQhEbPxR8I= +-----END PRIVATE KEY-----` + + vi.stubEnv("AURA_AUTH_PUBLIC_KEY", publicKey) + vi.stubEnv("AURA_AUTH_PRIVATE_KEY", privateKey) + + const jwt = createJoseInstance(undefined, { + jwt: { + mode: "sealed", + signingAlgorithm: "RS256", + keyAlgorithm: "RSA-OAEP-256", + encryptionAlgorithm: "A256GCM", + importedAlgorithm: "RSA-OAEP-256", + }, + }) + + await expect(jwt.encodeJWT(payload)).rejects.toThrow(/JWS signing failed/) + //const token = await jwt.encodeJWT(payload) + //const decoded = await jwt.decodeJWT(token) + //expect(decoded).toMatchObject(payload) + }) }) From 39e3159998d7c4b327aa52e1b32b199004d47a65 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Tue, 28 Apr 2026 10:47:56 -0500 Subject: [PATCH 2/5] feat(core): add support to PEM format in `sealed` mode --- packages/core/src/@types/session.ts | 67 +++++++--------- packages/core/src/jose.ts | 107 ++++++++++++++++++------- packages/core/src/shared/assert.ts | 32 ++++++-- packages/core/src/shared/crypto.ts | 19 ++++- packages/core/src/shared/errors.ts | 12 +++ packages/core/test/env.test.ts | 8 +- packages/core/test/jose.test.ts | 118 +++++++++------------------- packages/core/test/presets.ts | 88 +++++++++++++++++++++ 8 files changed, 292 insertions(+), 159 deletions(-) diff --git a/packages/core/src/@types/session.ts b/packages/core/src/@types/session.ts index 0b99d82..a353579 100644 --- a/packages/core/src/@types/session.ts +++ b/packages/core/src/@types/session.ts @@ -1,7 +1,7 @@ import type { infer as Infer } from "zod/v4/core" import type { TypedJWTPayload } from "@aura-stack/jose" import type { UserIdentity, UserShape } from "@/shared/identity.ts" -import type { DeepPartial, EditableShape, ZodShapeToObject } from "@/@types/utility.ts" +import type { DeepPartial, EditableShape, Prettify, ZodShapeToObject } from "@/@types/utility.ts" import type { CookieStoreConfig, IdentityConfig, InternalLogger, JoseInstance } from "@/@types/config.ts" /** Application user type, inferred from the configured identity schema (defaults to the built-in user shape). */ @@ -114,43 +114,34 @@ export type JWTConfigBase = JWTSignedMode | JWTEncryptedMode | JWTSealedMode /** How session/JWT lifetime is enforced relative to `iat`, absolute caps, and sliding windows. */ export type JWTExpirationStrategy = "fixed" | "rolling" | "absolute" | "sliding" -export type JWTConfig = { - /** - * Token lifetime. - */ - maxAge?: number - /** - * JWT `iss` (issuer) claim. Set this to your app's canonical URL. - * @example "https://auth.example.com" - */ - issuer?: string - /** - * JWT `aud` claim. Single value or array for multi-audience tokens. - * @example ["https://api.example.com", "https://app.example.com"] - */ - audience?: string | string[] - /** - * Maximum absolute session duration in seconds. - * Required for "absolute" and "sliding" strategies. - * Enforced via jose's maxTokenAge against the iat claim. - */ - maxExpiration?: number - /** - * Policy for renewing or capping token lifetime (pairs with `maxExpiration` where applicable). - */ - expirationStrategy?: JWTExpirationStrategy - /** - * Optional algorithm override for key import when using PEM-formatted keys from environment variables. - * - * > Currently only supported for `signed` and `encrypted` JWT modes and not for `sealed` mode. - * - * @todo Add `AURA_AUTH_SIGNING_PUBLIC|PRIVATE_KEY` and `AURA_AUTH_ENCRYPTION_PUBLIC|PRIVATE_KEY` env var - * support for separate signing/encryption keys in sealed mode, which would also require supporting separate - * algorithm overrides for each key (e.g. `AURA_AUTH_SIGNING_ALGORITHM` and `AURA_AUTH_ENCRYPTION_ALGORITHM`). - * @default "RS256" - */ - importedAlgorithm?: JWTSigningAlgorithm | JWTKeyAlgorithm -} & JWTConfigBase +export type JWTConfig = Prettify< + { + /** + * Token lifetime. + */ + maxAge?: number + /** + * JWT `iss` (issuer) claim. Set this to your app's canonical URL. + * @example "https://auth.example.com" + */ + issuer?: string + /** + * JWT `aud` claim. Single value or array for multi-audience tokens. + * @example ["https://api.example.com", "https://app.example.com"] + */ + audience?: string | string[] + /** + * Maximum absolute session duration in seconds. + * Required for "absolute" and "sliding" strategies. + * Enforced via jose's maxTokenAge against the iat claim. + */ + maxExpiration?: number + /** + * Policy for renewing or capping token lifetime (pairs with `maxExpiration` where applicable). + */ + expirationStrategy?: JWTExpirationStrategy + } & JWTConfigBase +> /** * Stateless JWT strategy. diff --git a/packages/core/src/jose.ts b/packages/core/src/jose.ts index 0d1070d..53bad07 100644 --- a/packages/core/src/jose.ts +++ b/packages/core/src/jose.ts @@ -14,26 +14,20 @@ import { type JWTDecryptOptions, } from "@aura-stack/jose" export { base64url, type JWTPayload } from "@aura-stack/jose/jose" -import { AuthInternalError, AuthSecurityError } from "@/shared/errors.ts" +import { AuthInternalError, AuthJoseInitializationError, AuthSecurityError } from "@/shared/errors.ts" import { isCryptoKey, isCryptoKeyPair, isCryptoSecret, isEncryptedMode, - isPemFormattedKeyPairFromEnv, + isJWTPEMFormattedKeyPair, + isPEMFormattedKeyPairFromEnv, isSealedMode, isSignedMode, } from "@/shared/assert.ts" export { encoder, getRandomBytes, getSubtleCrypto } from "@aura-stack/jose/crypto" -import type { - User, - SessionConfig, - JWTKey, - AsymmetricKeyPairFromEnv, - JWTSigningAlgorithm, - JWTKeyAlgorithm, -} from "@/@types/index.ts" -import { importPKCS8, importSPKI } from "@aura-stack/jose/jose" +import type { User, SessionConfig, JWTKey, AsymmetricKeyPairFromEnv } from "@/@types/index.ts" +import { importPEMKeyPair } from "./shared/crypto.ts" const getJWTConfig = (config?: SessionConfig) => { return config?.jwt @@ -119,27 +113,66 @@ export const verifyMaxExpiration = (payload: TypedJWTPayload>) => } const getSecrets = async ( - secret: JWTKey | AsymmetricKeyPairFromEnv, + secret: JWTKey | AsymmetricKeyPairFromEnv | { sign: AsymmetricKeyPairFromEnv; encrypt: AsymmetricKeyPairFromEnv }, salt: string, - importedAlgorithm?: JWTSigningAlgorithm | JWTKeyAlgorithm + session?: SessionConfig ) => { - if (isPemFormattedKeyPairFromEnv(secret)) { - const { publicKey, privateKey } = secret - const algorithm = getEnv("ALGORITHM") ?? getEnv("ALG") ?? importedAlgorithm ?? "RS256" - const importedPrivateKey = await importPKCS8(privateKey, algorithm, { extractable: true }) - const importedPublicKey = await importSPKI(publicKey, algorithm, { extractable: true }) + if (isJWTPEMFormattedKeyPair(secret)) { + if (!isSealedMode(session)) { + throw new AuthJoseInitializationError( + "INVALID_PEM_KEY_PAIR", + "Multiples PEM Key Pairs from environment variables require 'sealed' JWT mode. For 'signed' or 'encrypted' modes, provide a single PEM key pair or a combined key object." + ) + } + + const { sign, encrypt } = secret + const signingAlg = getEnv("SIGNING_ALG") || getEnv("SIGNING_ALGORITHM") || session?.jwt.signingAlgorithm || "RS256" + const encryptionAlg = + getEnv("ENCRYPTION_ALG") || getEnv("ENCRYPTION_ALGORITHM") || session?.jwt.keyAlgorithm || "RSA-OAEP-256" + const importedSign = await importPEMKeyPair(sign, signingAlg) + const importedEncrypt = await importPEMKeyPair(encrypt, encryptionAlg) + + return { + jwsSecret: importedSign, + jweSecret: importedEncrypt, + jwtSecret: { + sign: importedSign, + encrypt: importedEncrypt, + }, + } + } + if (isPEMFormattedKeyPairFromEnv(secret)) { + if (isSealedMode(session)) { + throw new AuthJoseInitializationError( + "INVALID_PEM_KEY_PAIR", + "Single PEM key pairs from environment variables require 'signed' or 'encrypted' JWT mode. For 'sealed' mode, provide separate signing and encryption keys or a combined key object." + ) + } + const algorithm = + getEnv("ALGORITHM") || + getEnv("ALG") || + (isSignedMode(session) ? session?.jwt?.signingAlgorithm : undefined) || + (isEncryptedMode(session) ? session?.jwt?.keyAlgorithm : undefined) || + "RS256" + const { publicKey, privateKey } = await importPEMKeyPair(secret, algorithm) return { jwsSecret: { - publicKey: importedPublicKey, - privateKey: importedPrivateKey, + publicKey, + privateKey, }, jweSecret: { - publicKey: importedPublicKey, - privateKey: importedPrivateKey, + publicKey, + privateKey, }, jwtSecret: { - sign: importedPrivateKey, - encrypt: importedPublicKey, + sign: { + publicKey, + privateKey, + }, + encrypt: { + publicKey, + privateKey, + }, }, } } @@ -179,13 +212,29 @@ const getSecrets = async ( } } +const getPEMKeyFromEnv = (prefix: string): AsymmetricKeyPairFromEnv | null => { + const publicKey = getEnv(`${prefix}${prefix && "_"}PUBLIC_KEY`) + const privateKey = getEnv(`${prefix}${prefix && "_"}PRIVATE_KEY`) + if (publicKey && privateKey) { + return { publicKey, privateKey } + } + return null +} + const getSecretKey = (secret?: JWTKey) => { secret ??= getEnv("SECRET") if (secret) return secret - const publicKey = getEnv("PUBLIC_KEY") - const privateKey = getEnv("PRIVATE_KEY") - if (publicKey && privateKey) { - return { publicKey, privateKey } + const pem = getPEMKeyFromEnv("") + if (pem) { + return pem + } + const signing = getPEMKeyFromEnv("SIGNING") + const encryption = getPEMKeyFromEnv("ENCRYPTION") + if (signing && encryption) { + return { + sign: signing, + encrypt: encryption, + } } throw new AuthInternalError( "JOSE_INITIALIZATION_FAILED", @@ -227,7 +276,7 @@ export const createJoseInstance = (secret?: JWT } const jose = (async () => { - const { jwsSecret, jweSecret, jwtSecret } = await getSecrets(secretKey, salt, session?.jwt?.importedAlgorithm) + const { jwsSecret, jweSecret, jwtSecret } = await getSecrets(secretKey, salt, session) return { jwt: createJWT(jwtSecret), diff --git a/packages/core/src/shared/assert.ts b/packages/core/src/shared/assert.ts index 502366c..046e63e 100644 --- a/packages/core/src/shared/assert.ts +++ b/packages/core/src/shared/assert.ts @@ -1,5 +1,12 @@ import { equals, patternToRegex } from "@/shared/utils.ts" -import type { CryptoSecret, JWTConfig, JWTMode, JWTPayloadWithToken, SessionConfig } from "@/@types/index.ts" +import type { + AsymmetricKeyPairFromEnv, + CryptoSecret, + JWTConfig, + JWTMode, + JWTPayloadWithToken, + SessionConfig, +} from "@/@types/index.ts" export const isFalsy = (value: unknown): boolean => { return value === false || value === 0 || value === "" || value === null || value === undefined || Number.isNaN(value) @@ -107,7 +114,7 @@ export const isSignedMode = (config?: SessionConfig): config is { jwt: Extract } => getJWTMode(config) === "encrypted" -export const isSealedMode = (config?: SessionConfig): config is { jwt: Extract } => +export const isSealedMode = (config?: SessionConfig): config is { jwt: Extract } => getJWTMode(config) === "sealed" export const isCryptoKeyPair = (value: unknown): value is CryptoKeyPair => { @@ -129,17 +136,30 @@ export const isCryptoSecret = (value: unknown): value is CryptoSecret => { ) } -export const isPemFormattedKey = (value: unknown): value is string => { +export const isPEMFormattedKey = (value: unknown): value is string => { return typeof value === "string" && /-----BEGIN (PUBLIC|PRIVATE) KEY-----/.test(value) } -export const isPemFormattedKeyPairFromEnv = (value: unknown): value is { publicKey: string; privateKey: string } => { +export const isPEMFormattedKeyPairFromEnv = (value: unknown): value is { publicKey: string; privateKey: string } => { return ( typeof value === "object" && value !== null && "publicKey" in value && "privateKey" in value && - isPemFormattedKey(value.publicKey) && - isPemFormattedKey(value.privateKey) + isPEMFormattedKey(value.publicKey) && + isPEMFormattedKey(value.privateKey) + ) +} + +export const isJWTPEMFormattedKeyPair = ( + value: unknown +): value is { sign: AsymmetricKeyPairFromEnv; encrypt: AsymmetricKeyPairFromEnv } => { + return ( + typeof value === "object" && + value !== null && + "sign" in value && + "encrypt" in value && + isPEMFormattedKeyPairFromEnv((value as any).sign) && + isPEMFormattedKeyPairFromEnv((value as any).encrypt) ) } diff --git a/packages/core/src/shared/crypto.ts b/packages/core/src/shared/crypto.ts index 5e44327..d509104 100644 --- a/packages/core/src/shared/crypto.ts +++ b/packages/core/src/shared/crypto.ts @@ -1,8 +1,9 @@ import { AuthSecurityError } from "@/shared/errors.ts" import { isJWTPayloadWithToken } from "@/shared/assert.ts" import { equals, timingSafeEqual } from "@/shared/utils.ts" +import { importPKCS8, importSPKI } from "@aura-stack/jose/jose" import { base64url, encoder, getRandomBytes, getSubtleCrypto } from "@/jose.ts" -import type { AuthRuntimeConfig, JoseInstance, User } from "@/@types/index.ts" +import type { AsymmetricKeyPairFromEnv, AuthRuntimeConfig, JoseInstance, User } from "@/@types/index.ts" export { generateKeyPair as createKeyPair } from "@aura-stack/jose/jose" @@ -134,3 +135,19 @@ export const verifyPassword = async (password: string, hashedPassword: string) = return false } } + +/** + * Imports a PEM-formatted asymmetric key pair from strings. + * + * @param key - An object containing the public and private keys as PEM-formatted strings + * @param algorithm - The intended algorithm for the keys (e.g. "RS256" for RSA signing, "RSA-OAEP" for RSA encryption) + * @returns A Promise that resolves to a CryptoKeyPair with the imported keys + */ +export const importPEMKeyPair = async (key: AsymmetricKeyPairFromEnv, algorithm: string) => { + const importedPrivateKey = await importPKCS8(key.privateKey, algorithm, { extractable: true }) + const importedPublicKey = await importSPKI(key.publicKey, algorithm, { extractable: true }) + return { + publicKey: importedPublicKey, + privateKey: importedPrivateKey, + } +} diff --git a/packages/core/src/shared/errors.ts b/packages/core/src/shared/errors.ts index 02ecc00..b5f4f36 100644 --- a/packages/core/src/shared/errors.ts +++ b/packages/core/src/shared/errors.ts @@ -91,6 +91,18 @@ export class AuthValidationError extends Error { } } +export class AuthJoseInitializationError extends Error { + readonly type = "JOSE_INITIALIZATION_FAILED" + readonly code: string + + constructor(code: string, message?: string, options?: ErrorOptions) { + super(message, options) + this.code = code + this.name = new.target.name + Error?.captureStackTrace?.(this, new.target) + } +} + export const isNativeError = (error: unknown): error is Error => { return error instanceof Error } diff --git a/packages/core/test/env.test.ts b/packages/core/test/env.test.ts index 0f3d613..c8ecbb1 100644 --- a/packages/core/test/env.test.ts +++ b/packages/core/test/env.test.ts @@ -47,7 +47,11 @@ describe("env", () => { const keyPair = await generateKeyPair("RS256", { extractable: true }) const publicKeyPEM = await exportSPKI(keyPair.publicKey) const privateKeyPEM = await exportPKCS8(keyPair.privateKey) - vi.stubEnv("AURA_AUTH_SECRET", `${publicKeyPEM}\n${privateKeyPEM}`) - expect(env.AURA_AUTH_SECRET).toBe(`${publicKeyPEM}\n${privateKeyPEM}`) + vi.stubEnv("AURA_AUTH_PUBLIC_KEY", publicKeyPEM) + vi.stubEnv("AURA_AUTH_PRIVATE_KEY", privateKeyPEM) + vi.stubEnv("ALG", "RS256") + expect(env.AURA_AUTH_PUBLIC_KEY).toBe(publicKeyPEM) + expect(env.AURA_AUTH_PRIVATE_KEY).toBe(privateKeyPEM) + expect(env.ALG).toBe("RS256") }) }) diff --git a/packages/core/test/jose.test.ts b/packages/core/test/jose.test.ts index 96700ad..5bf4eab 100644 --- a/packages/core/test/jose.test.ts +++ b/packages/core/test/jose.test.ts @@ -3,6 +3,7 @@ import { createJoseInstance, encoder } from "@/jose.ts" import { createSecretValue } from "@/shared/crypto.ts" import { createAuth } from "@/createAuth.ts" import { generateKeyPair } from "@aura-stack/jose/jose" +import { RS256PEMFormat, RSAOAEP256PEMFormat } from "./presets.ts" const payload = { sub: "1234567890", @@ -543,46 +544,11 @@ describe("createJoseInstance", () => { test("PEM formatted RSA keys", async () => { vi.stubEnv("AURA_AUTH_SALT", createSecretValue(32)) - const publicKey = `-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5eSIl71g3dyLEFYbv3B -i93M9nCBLWkbI8mOQLmGgXEj3k92rwfF/+B5gCr1OMUmV+aSLsDvdhDiljQAUpQO -3ziLaYlk0k8paw7fZjkIejz5BwiWFODTqg9HWSOGr5hfJzyL9gvzaAI2Sp7htei/ -En0u79eRNQNII0dmQtwiMpIEQbisadUEp5+s0Dd7yGUoR18V7pv2A/Ohii8lMUUL -Efs71Ypf0L5rO9SAhjztxhR6wGWYe+uCNDEF0wuQ/ZL9TvI46Zpf+Z1z+0CzpXYr -Eloe8oqcCuPIJ1GszZst+qkgFdyo0BXGa1nuA/21ZLmAwUXdzmF1nsGg0J/sUcEQ -TwIDAQAB ------END PUBLIC KEY-----` - const privateKey = `-----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/l5IiXvWDd3Is -QVhu/cGL3cz2cIEtaRsjyY5AuYaBcSPeT3avB8X/4HmAKvU4xSZX5pIuwO92EOKW -NABSlA7fOItpiWTSTylrDt9mOQh6PPkHCJYU4NOqD0dZI4avmF8nPIv2C/NoAjZK -nuG16L8SfS7v15E1A0gjR2ZC3CIykgRBuKxp1QSnn6zQN3vIZShHXxXum/YD86GK -LyUxRQsR+zvVil/Qvms71ICGPO3GFHrAZZh764I0MQXTC5D9kv1O8jjpml/5nXP7 -QLOldisSWh7yipwK48gnUazNmy36qSAV3KjQFcZrWe4D/bVkuYDBRd3OYXWewaDQ -n+xRwRBPAgMBAAECggEACh2r77IMck7cUbDexSsTZo0LlUsWzvmya9ib10s60MFs -1hnJyu91CVyy6maaQJwyn5TpgAJCdbBQWANSRwnq1RqZTDVSBCnkDNm7eukk/otG -NmEolENteZh8uTY/SZMygJHzIK0iqQm0D/GR0+oZ+JU9seUzlTuuOeQ7TOluY5wR -i/V6ldrDSOxd2xIKUnxemw0qwbUz0oZ5CKo22K+VksGwa/PempkpyZloSGsE+QR5 -5cZwWxGelzUCDyflOImX+TCKI4IsuBOI+CaQohY3j3xSEunSyE4BCITgtIjlHJOB -OspOYs/rYQt9xe1ZzBlRTbq/iZAonMgRS1ELm75eWQKBgQD2dlyaZIMpuhKWBWgb -tPC0CrPLxOqWi5TSkaR+kk389xOqi6m62mPph5dCxv/TrvrXD+v/uST2aAYPnLSY -3ieVF+KN5fc64M2rgUYR9kOE0ubiir1RI7L7yhYo/bmtSnpd1Wr6vJBU6zEBayTL -X4Uw+nABrO/Si5SEssb9LGF/RwKBgQDHAZ+iiOhzOJCp9kCqHYJ5ageNVT/Fc85W -40pYSAiuPlolJV43oG0EnFI7MVkvqSExHfNtk7PgQsahPTsWThJRL4stzbBINmDW -Fxl505BOoXhnJHLqnQgzmNTinnupumnENImm5ChWbujRREi6kIiZYqUlKjQjN1j1 -9TTGCto6uQKBgQCb6NA30vGuSclMIetz64iBPGv0sYL87RueAQggEYlIRzynnGYo -j9K4fk/PrHdVf9GqjqXqRUL+pVuAMM+GDLLZfByTSzCUjHVO0x5yamjX81qfYMjW -NVEaOwK9t5Pn7b9u8H0WVIaxUX7UuOSzyp9FFogYZz/m3ul68GU07whWLQKBgEhP -Mbb4MiYzpnTrUmG9qTv+p9HV6P8Q7ieqHMhpHCZb55tZsZtawmILfuGdM7/an4He -VSY6pgBVoyDRQ9f99C/lq5ewBl6my5be+9XFZsj7aOlpWAwhlOpSnP/fACYS4v10 -7ZNjkbieQiBPxHFttQSu0Dzp0dn98WgledB//v2ZAoGAFdsS7VxBMCBcJIgPoYiX -GDUYZsTiISPnSRqRk1hXkRt1woAa8CK3zsCyrruoCj3VJFk6gb+TWuyBXv4kfRkv -TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA -41a79/alPIgWSGQhEbPxR8I= ------END PRIVATE KEY-----` + const { publicKey, privateKey } = RS256PEMFormat vi.stubEnv("AURA_AUTH_PUBLIC_KEY", publicKey) vi.stubEnv("AURA_AUTH_PRIVATE_KEY", privateKey) + const jws = createJoseInstance(undefined, { jwt: { mode: "signed", @@ -598,58 +564,36 @@ TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA mode: "encrypted", keyAlgorithm: "RSA-OAEP-256", encryptionAlgorithm: "A256GCM", - importedAlgorithm: "RSA-OAEP-256", }, }) const encrypted = await jwe.encryptJWE(payload) const decrypted = await jwe.decryptJWE(encrypted) expect(decrypted).toMatchObject(payload) + + const jwt = createJoseInstance(undefined, { + jwt: { + mode: "sealed", + signingAlgorithm: "RS256", + keyAlgorithm: "RSA-OAEP-256", + encryptionAlgorithm: "A256GCM", + }, + }) + await expect(jwt.encodeJWT(payload)).rejects.toThrow( + /Single PEM key pairs from environment variables require 'signed' or 'encrypted' JWT mode. For 'sealed' mode, provide separate signing and encryption keys or a combined key object./ + ) }) - test("PEM formatted RSA keys to encode and decode JWT", async () => { + test("PEM formatted RSA keys for sealed mode", async () => { vi.stubEnv("AURA_AUTH_SALT", createSecretValue(32)) - const publicKey = `-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5eSIl71g3dyLEFYbv3B -i93M9nCBLWkbI8mOQLmGgXEj3k92rwfF/+B5gCr1OMUmV+aSLsDvdhDiljQAUpQO -3ziLaYlk0k8paw7fZjkIejz5BwiWFODTqg9HWSOGr5hfJzyL9gvzaAI2Sp7htei/ -En0u79eRNQNII0dmQtwiMpIEQbisadUEp5+s0Dd7yGUoR18V7pv2A/Ohii8lMUUL -Efs71Ypf0L5rO9SAhjztxhR6wGWYe+uCNDEF0wuQ/ZL9TvI46Zpf+Z1z+0CzpXYr -Eloe8oqcCuPIJ1GszZst+qkgFdyo0BXGa1nuA/21ZLmAwUXdzmF1nsGg0J/sUcEQ -TwIDAQAB ------END PUBLIC KEY-----` - const privateKey = `-----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/l5IiXvWDd3Is -QVhu/cGL3cz2cIEtaRsjyY5AuYaBcSPeT3avB8X/4HmAKvU4xSZX5pIuwO92EOKW -NABSlA7fOItpiWTSTylrDt9mOQh6PPkHCJYU4NOqD0dZI4avmF8nPIv2C/NoAjZK -nuG16L8SfS7v15E1A0gjR2ZC3CIykgRBuKxp1QSnn6zQN3vIZShHXxXum/YD86GK -LyUxRQsR+zvVil/Qvms71ICGPO3GFHrAZZh764I0MQXTC5D9kv1O8jjpml/5nXP7 -QLOldisSWh7yipwK48gnUazNmy36qSAV3KjQFcZrWe4D/bVkuYDBRd3OYXWewaDQ -n+xRwRBPAgMBAAECggEACh2r77IMck7cUbDexSsTZo0LlUsWzvmya9ib10s60MFs -1hnJyu91CVyy6maaQJwyn5TpgAJCdbBQWANSRwnq1RqZTDVSBCnkDNm7eukk/otG -NmEolENteZh8uTY/SZMygJHzIK0iqQm0D/GR0+oZ+JU9seUzlTuuOeQ7TOluY5wR -i/V6ldrDSOxd2xIKUnxemw0qwbUz0oZ5CKo22K+VksGwa/PempkpyZloSGsE+QR5 -5cZwWxGelzUCDyflOImX+TCKI4IsuBOI+CaQohY3j3xSEunSyE4BCITgtIjlHJOB -OspOYs/rYQt9xe1ZzBlRTbq/iZAonMgRS1ELm75eWQKBgQD2dlyaZIMpuhKWBWgb -tPC0CrPLxOqWi5TSkaR+kk389xOqi6m62mPph5dCxv/TrvrXD+v/uST2aAYPnLSY -3ieVF+KN5fc64M2rgUYR9kOE0ubiir1RI7L7yhYo/bmtSnpd1Wr6vJBU6zEBayTL -X4Uw+nABrO/Si5SEssb9LGF/RwKBgQDHAZ+iiOhzOJCp9kCqHYJ5ageNVT/Fc85W -40pYSAiuPlolJV43oG0EnFI7MVkvqSExHfNtk7PgQsahPTsWThJRL4stzbBINmDW -Fxl505BOoXhnJHLqnQgzmNTinnupumnENImm5ChWbujRREi6kIiZYqUlKjQjN1j1 -9TTGCto6uQKBgQCb6NA30vGuSclMIetz64iBPGv0sYL87RueAQggEYlIRzynnGYo -j9K4fk/PrHdVf9GqjqXqRUL+pVuAMM+GDLLZfByTSzCUjHVO0x5yamjX81qfYMjW -NVEaOwK9t5Pn7b9u8H0WVIaxUX7UuOSzyp9FFogYZz/m3ul68GU07whWLQKBgEhP -Mbb4MiYzpnTrUmG9qTv+p9HV6P8Q7ieqHMhpHCZb55tZsZtawmILfuGdM7/an4He -VSY6pgBVoyDRQ9f99C/lq5ewBl6my5be+9XFZsj7aOlpWAwhlOpSnP/fACYS4v10 -7ZNjkbieQiBPxHFttQSu0Dzp0dn98WgledB//v2ZAoGAFdsS7VxBMCBcJIgPoYiX -GDUYZsTiISPnSRqRk1hXkRt1woAa8CK3zsCyrruoCj3VJFk6gb+TWuyBXv4kfRkv -TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA -41a79/alPIgWSGQhEbPxR8I= ------END PRIVATE KEY-----` + const { publicKey: jwsPublicKey, privateKey: jwsPrivateKey } = RS256PEMFormat + const { publicKey: jwePublicKey, privateKey: jwePrivateKey } = RSAOAEP256PEMFormat - vi.stubEnv("AURA_AUTH_PUBLIC_KEY", publicKey) - vi.stubEnv("AURA_AUTH_PRIVATE_KEY", privateKey) + vi.stubEnv("AURA_AUTH_SIGNING_PUBLIC_KEY", jwsPublicKey) + vi.stubEnv("AURA_AUTH_SIGNING_PRIVATE_KEY", jwsPrivateKey) + vi.stubEnv("AURA_AUTH_ENCRYPTION_PUBLIC_KEY", jwePublicKey) + vi.stubEnv("AURA_AUTH_ENCRYPTION_PRIVATE_KEY", jwePrivateKey) const jwt = createJoseInstance(undefined, { jwt: { @@ -657,13 +601,21 @@ TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA signingAlgorithm: "RS256", keyAlgorithm: "RSA-OAEP-256", encryptionAlgorithm: "A256GCM", - importedAlgorithm: "RSA-OAEP-256", }, }) - await expect(jwt.encodeJWT(payload)).rejects.toThrow(/JWS signing failed/) - //const token = await jwt.encodeJWT(payload) - //const decoded = await jwt.decodeJWT(token) - //expect(decoded).toMatchObject(payload) + const token = await jwt.encodeJWT(payload) + const decoded = await jwt.decodeJWT(token) + expect(decoded).toMatchObject(payload) + + const jws = createJoseInstance(undefined, { + jwt: { + mode: "signed", + signingAlgorithm: "RS256", + }, + }) + await expect(jws.signJWS(payload)).rejects.toThrow( + /Multiples PEM Key Pairs from environment variables require 'sealed' JWT mode. For 'signed' or 'encrypted' modes, provide a single PEM key pair or a combined key object./ + ) }) }) diff --git a/packages/core/test/presets.ts b/packages/core/test/presets.ts index 01e6731..1c742b0 100644 --- a/packages/core/test/presets.ts +++ b/packages/core/test/presets.ts @@ -56,3 +56,91 @@ export const { jose, api, } = auth + +const RSA256PublicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5eSIl71g3dyLEFYbv3B +i93M9nCBLWkbI8mOQLmGgXEj3k92rwfF/+B5gCr1OMUmV+aSLsDvdhDiljQAUpQO +3ziLaYlk0k8paw7fZjkIejz5BwiWFODTqg9HWSOGr5hfJzyL9gvzaAI2Sp7htei/ +En0u79eRNQNII0dmQtwiMpIEQbisadUEp5+s0Dd7yGUoR18V7pv2A/Ohii8lMUUL +Efs71Ypf0L5rO9SAhjztxhR6wGWYe+uCNDEF0wuQ/ZL9TvI46Zpf+Z1z+0CzpXYr +Eloe8oqcCuPIJ1GszZst+qkgFdyo0BXGa1nuA/21ZLmAwUXdzmF1nsGg0J/sUcEQ +TwIDAQAB +-----END PUBLIC KEY-----` + +const RSA256PrivateKey = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/l5IiXvWDd3Is +QVhu/cGL3cz2cIEtaRsjyY5AuYaBcSPeT3avB8X/4HmAKvU4xSZX5pIuwO92EOKW +NABSlA7fOItpiWTSTylrDt9mOQh6PPkHCJYU4NOqD0dZI4avmF8nPIv2C/NoAjZK +nuG16L8SfS7v15E1A0gjR2ZC3CIykgRBuKxp1QSnn6zQN3vIZShHXxXum/YD86GK +LyUxRQsR+zvVil/Qvms71ICGPO3GFHrAZZh764I0MQXTC5D9kv1O8jjpml/5nXP7 +QLOldisSWh7yipwK48gnUazNmy36qSAV3KjQFcZrWe4D/bVkuYDBRd3OYXWewaDQ +n+xRwRBPAgMBAAECggEACh2r77IMck7cUbDexSsTZo0LlUsWzvmya9ib10s60MFs +1hnJyu91CVyy6maaQJwyn5TpgAJCdbBQWANSRwnq1RqZTDVSBCnkDNm7eukk/otG +NmEolENteZh8uTY/SZMygJHzIK0iqQm0D/GR0+oZ+JU9seUzlTuuOeQ7TOluY5wR +i/V6ldrDSOxd2xIKUnxemw0qwbUz0oZ5CKo22K+VksGwa/PempkpyZloSGsE+QR5 +5cZwWxGelzUCDyflOImX+TCKI4IsuBOI+CaQohY3j3xSEunSyE4BCITgtIjlHJOB +OspOYs/rYQt9xe1ZzBlRTbq/iZAonMgRS1ELm75eWQKBgQD2dlyaZIMpuhKWBWgb +tPC0CrPLxOqWi5TSkaR+kk389xOqi6m62mPph5dCxv/TrvrXD+v/uST2aAYPnLSY +3ieVF+KN5fc64M2rgUYR9kOE0ubiir1RI7L7yhYo/bmtSnpd1Wr6vJBU6zEBayTL +X4Uw+nABrO/Si5SEssb9LGF/RwKBgQDHAZ+iiOhzOJCp9kCqHYJ5ageNVT/Fc85W +40pYSAiuPlolJV43oG0EnFI7MVkvqSExHfNtk7PgQsahPTsWThJRL4stzbBINmDW +Fxl505BOoXhnJHLqnQgzmNTinnupumnENImm5ChWbujRREi6kIiZYqUlKjQjN1j1 +9TTGCto6uQKBgQCb6NA30vGuSclMIetz64iBPGv0sYL87RueAQggEYlIRzynnGYo +j9K4fk/PrHdVf9GqjqXqRUL+pVuAMM+GDLLZfByTSzCUjHVO0x5yamjX81qfYMjW +NVEaOwK9t5Pn7b9u8H0WVIaxUX7UuOSzyp9FFogYZz/m3ul68GU07whWLQKBgEhP +Mbb4MiYzpnTrUmG9qTv+p9HV6P8Q7ieqHMhpHCZb55tZsZtawmILfuGdM7/an4He +VSY6pgBVoyDRQ9f99C/lq5ewBl6my5be+9XFZsj7aOlpWAwhlOpSnP/fACYS4v10 +7ZNjkbieQiBPxHFttQSu0Dzp0dn98WgledB//v2ZAoGAFdsS7VxBMCBcJIgPoYiX +GDUYZsTiISPnSRqRk1hXkRt1woAa8CK3zsCyrruoCj3VJFk6gb+TWuyBXv4kfRkv +TGcJZ3AYFKmelXl+1+rRXhe+f79+Z8kRdRSonuG/l1PdtG3P1uglzvksQcSMfOfA +41a79/alPIgWSGQhEbPxR8I= +-----END PRIVATE KEY-----` + +const RSAOAEP256PublicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqFSzD1nqVd91MIYMxqdG +le/v4BFyNFcdWQgFcxGcfOy+r2tpnGEgN7WmDe/59MGwGP1/al74qWJLvEkqBW/b +QCEyVX8KcL47p1N88efwR4wBiNseb+qYfdEvb00np8UVhK4QnJlUNHI5t/I9xQr7 +9cieQEGb4C5SzUsetzlVsPq5r0fqOhE8j3mDoGrQO7n6Uc3xssebNNeLTBei4YPr +2FTbgI9jGYiR8fOgefSSZUAqP7MIhEzpgqBMYQ1IYhoDMR//S5ftye78X266MHCR +501DT1lkGX3Eem2C8lT8TONyCx4bORIs3401PsfzgEyl4dRvngIE6Qqmvn5zQSkF +RwIDAQAB +-----END PUBLIC KEY-----` + +const RSAOAEP256PrivateKey = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCoVLMPWepV33Uw +hgzGp0aV7+/gEXI0Vx1ZCAVzEZx87L6va2mcYSA3taYN7/n0wbAY/X9qXvipYku8 +SSoFb9tAITJVfwpwvjunU3zx5/BHjAGI2x5v6ph90S9vTSenxRWErhCcmVQ0cjm3 +8j3FCvv1yJ5AQZvgLlLNSx63OVWw+rmvR+o6ETyPeYOgatA7ufpRzfGyx5s014tM +F6Lhg+vYVNuAj2MZiJHx86B59JJlQCo/swiETOmCoExhDUhiGgMxH/9Ll+3J7vxf +browcJHnTUNPWWQZfcR6bYLyVPxM43ILHhs5EizfjTU+x/OATKXh1G+eAgTpCqa+ +fnNBKQVHAgMBAAECggEAOX/ZPHSv5c5zdvRLV+5a36u6qjT7aGKbjUZ+qgxJgqjS +CBTuWfMZcL41b0xaex9QWnD5PaocUavYiAQL/Rh08eaFDYxcUh/BO8p6gx2Bx8bM +3WVP89XUaiHzDJdz5MyfKZfV59A+Yb3k9m8iZ3T1lUMGv5dJuh3IvgSbhOXqXg3x +SE2UqsGGx5/IEvqRcLZ9GMjp/yOPyjwUmqfuN6xPuy698EdLJgzrfX0CCNBvdjsV +WT2SA1t4pptX+IPikXglsVokv/jEHIAdpNHQDzFLlAL89AxKg9K/7XD+xGkInFVD +JRKnFcXSS5Nt/n/P1ZnBghDxFwF6DV40hbaVK7+ZTQKBgQDXAlQPMF3XvC9Bah0f +YSW5yVv3nnr9gQmIcoghUgInOdRTvfagEwkDY1vh5FsQcgQOxyOgbT3yJcQAI32O +YBWVvaTHy6l4q3PL6ERkplz9aOKCAOH1Ds8JyyiyDtOdE/cylc1Kan+4eg68Lex0 +0kxNb4F5FYaFkyupR1xfh1JBfQKBgQDIbDTfTiDcAn61+d8DfS5HTLZCsaIo6g/Q +CJ36p70Cs80Js3n0nICOl6TZaIV5qco+VX6H2leQb9xR3ktTDOPUMuDnzf7X8+YO +y2TOF4phRs47i6S6mamu7rmfAh7Qr8GDiRQXbuX6gFYSFDFsPbLHCn2apOGyCsQF +VAN7mJ8dEwKBgQCuSRDijw5CxiR4HhAlU5ZFF1gZTLndrC+SD2URvWxJZ7MZfq7f +6w4vVOcyIO1AU2u+nuXeMS85jitnAV3Rf0l/7A4adpiVXEWtUEXAYKqYL+EMCLMg +9jQVeD0wuJwIhBqpQoz6eYG2hBpVp9Q4jg+T5YNKJ4y30iheO55BQWwH8QKBgBQE +ytsrIJkZHrLqfF4K2N6CSQosV/giOOYcljr9GiH095vqc1n9b9HOT8bva7WVQgAr +5fGH24svwR/kRj3LYc5GLrS4nKXRVL9RjYYQT+AbhGnqLs/8nTg93AiH27AYfgm3 +XWxhxVLaEr7HiZA4MW00HQufQHPaI24s0BQ+UFZFAoGALRr4XkBKSFSZXo5/zO85 +FwWzwouGrZmIlL4flHagvqx94ObCk+aKxR7H2oPdgb0FDIJu7h7XMrZo3T2jOjfp +3Rs0CexilYo91sin1Bu5/1fYuBEt/AP39t5cjyUhOooE+D+Bn1P6mvKnmZYPDdTR +B+P4zFojgfEO6TszdVGgCkU= +-----END PRIVATE KEY-----` + +export const RS256PEMFormat = { + publicKey: RSA256PublicKey, + privateKey: RSA256PrivateKey, +} + +export const RSAOAEP256PEMFormat = { + publicKey: RSAOAEP256PublicKey, + privateKey: RSAOAEP256PrivateKey, +} From 82eee74dda44f6c91a85aa3f963f45125606afea Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Tue, 28 Apr 2026 11:09:00 -0500 Subject: [PATCH 3/5] chore: update `.env.example` files --- apps/astro/.env.example | 98 +++++++++++------ apps/bun/.env.example | 96 ++++++++++------ apps/cloudflare/.env.example | 44 ++++++-- apps/deno/.env.example | 44 ++++++-- apps/elysia/.env.example | 96 ++++++++++------ apps/express/.env.example | 97 +++++++++++------ apps/hono/.env.example | 96 ++++++++++------ apps/nextjs/app-router/.env.example | 151 ++++++++++---------------- apps/nextjs/pages-router/.env.example | 97 +++++++++++------ apps/nuxt/.env.example | 97 +++++++++++------ apps/oak/.env.example | 96 ++++++++++------ apps/react-router/.env.example | 97 +++++++++++------ apps/supabase/.env.example | 44 ++++++-- apps/tanstack-start/.env.example | 97 +++++++++++------ apps/vercel/.env.example | 44 ++++++-- 15 files changed, 828 insertions(+), 466 deletions(-) diff --git a/apps/astro/.env.example b/apps/astro/.env.example index f0bb6cc..0ee2e20 100644 --- a/apps/astro/.env.example +++ b/apps/astro/.env.example @@ -1,66 +1,96 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= + # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/bun/.env.example b/apps/bun/.env.example index f5f67e6..e4bc6cf 100644 --- a/apps/bun/.env.example +++ b/apps/bun/.env.example @@ -1,67 +1,95 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/cloudflare/.env.example b/apps/cloudflare/.env.example index fce5ea0..e4bc6cf 100644 --- a/apps/cloudflare/.env.example +++ b/apps/cloudflare/.env.example @@ -1,11 +1,39 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 -AURA_AUTH_SALT= - -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 -AURA_AUTH_SECRET= - +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 +AURA_AUTH_SALT="" + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 +AURA_AUTH_SECRET="" + +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials AURA_AUTH_GITHUB_CLIENT_ID= AURA_AUTH_GITHUB_CLIENT_SECRET= diff --git a/apps/deno/.env.example b/apps/deno/.env.example index fce5ea0..e4bc6cf 100644 --- a/apps/deno/.env.example +++ b/apps/deno/.env.example @@ -1,11 +1,39 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 -AURA_AUTH_SALT= - -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 -AURA_AUTH_SECRET= - +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 +AURA_AUTH_SALT="" + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 +AURA_AUTH_SECRET="" + +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials AURA_AUTH_GITHUB_CLIENT_ID= AURA_AUTH_GITHUB_CLIENT_SECRET= diff --git a/apps/elysia/.env.example b/apps/elysia/.env.example index f5f67e6..e4bc6cf 100644 --- a/apps/elysia/.env.example +++ b/apps/elysia/.env.example @@ -1,67 +1,95 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/express/.env.example b/apps/express/.env.example index f0bb6cc..e4bc6cf 100644 --- a/apps/express/.env.example +++ b/apps/express/.env.example @@ -1,66 +1,95 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/hono/.env.example b/apps/hono/.env.example index f5f67e6..e4bc6cf 100644 --- a/apps/hono/.env.example +++ b/apps/hono/.env.example @@ -1,67 +1,95 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/nextjs/app-router/.env.example b/apps/nextjs/app-router/.env.example index 34d5cb8..e4bc6cf 100644 --- a/apps/nextjs/app-router/.env.example +++ b/apps/nextjs/app-router/.env.example @@ -1,132 +1,95 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 -AURA_AUTH_SECRET="" - -# Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" - -# Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" - -# Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" -# Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" - -# GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" - -# Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" - -# X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" - -# Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" - -# Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" - -# Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 +AURA_AUTH_SECRET="" -# Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= -# Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= -# Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= -# Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= -# TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" -# Opaque secret used to sign and verify JWT tokens +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= -# openssl rand -base64 32 -AURA_AUTH_SALT="" -# openssl rand -base64 32 -AURA_AUTH_SECRET="" +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/nextjs/pages-router/.env.example b/apps/nextjs/pages-router/.env.example index f0bb6cc..e4bc6cf 100644 --- a/apps/nextjs/pages-router/.env.example +++ b/apps/nextjs/pages-router/.env.example @@ -1,66 +1,95 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/nuxt/.env.example b/apps/nuxt/.env.example index f0bb6cc..e4bc6cf 100644 --- a/apps/nuxt/.env.example +++ b/apps/nuxt/.env.example @@ -1,66 +1,95 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/oak/.env.example b/apps/oak/.env.example index f5f67e6..e4bc6cf 100644 --- a/apps/oak/.env.example +++ b/apps/oak/.env.example @@ -1,67 +1,95 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/react-router/.env.example b/apps/react-router/.env.example index f0bb6cc..e4bc6cf 100644 --- a/apps/react-router/.env.example +++ b/apps/react-router/.env.example @@ -1,66 +1,95 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/supabase/.env.example b/apps/supabase/.env.example index fce5ea0..e4bc6cf 100644 --- a/apps/supabase/.env.example +++ b/apps/supabase/.env.example @@ -1,11 +1,39 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 -AURA_AUTH_SALT= - -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 -AURA_AUTH_SECRET= - +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 +AURA_AUTH_SALT="" + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 +AURA_AUTH_SECRET="" + +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials AURA_AUTH_GITHUB_CLIENT_ID= AURA_AUTH_GITHUB_CLIENT_SECRET= diff --git a/apps/tanstack-start/.env.example b/apps/tanstack-start/.env.example index f0bb6cc..e4bc6cf 100644 --- a/apps/tanstack-start/.env.example +++ b/apps/tanstack-start/.env.example @@ -1,66 +1,95 @@ -# Opaque secret used to sign and verify JWT tokens - -# openssl rand -base64 32 +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 AURA_AUTH_SALT="" -# openssl rand -base64 32 + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 AURA_AUTH_SECRET="" +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials -AURA_AUTH_GITHUB_CLIENT_ID="" -AURA_AUTH_GITHUB_CLIENT_SECRET="" +AURA_AUTH_GITHUB_CLIENT_ID= +AURA_AUTH_GITHUB_CLIENT_SECRET= # Bitbucket OAuth App Credentials -AURA_AUTH_BITBUCKET_CLIENT_ID="" -AURA_AUTH_BITBUCKET_CLIENT_SECRET="" +AURA_AUTH_BITBUCKET_CLIENT_ID= +AURA_AUTH_BITBUCKET_CLIENT_SECRET= # Figma OAuth App Credentials -AURA_AUTH_FIGMA_CLIENT_ID="" -AURA_AUTH_FIGMA_CLIENT_SECRET="" +AURA_AUTH_FIGMA_CLIENT_ID= +AURA_AUTH_FIGMA_CLIENT_SECRET= # Discord OAuth App Credentials -AURA_AUTH_DISCORD_CLIENT_ID="" -AURA_AUTH_DISCORD_CLIENT_SECRET="" +AURA_AUTH_DISCORD_CLIENT_ID= +AURA_AUTH_DISCORD_CLIENT_SECRET= # GitLab OAuth App Credentials -AURA_AUTH_GITLAB_CLIENT_ID="" -AURA_AUTH_GITLAB_CLIENT_SECRET="" +AURA_AUTH_GITLAB_CLIENT_ID= +AURA_AUTH_GITLAB_CLIENT_SECRET= # Spotify OAuth App Credentials -AURA_AUTH_SPOTIFY_CLIENT_ID="" -AURA_AUTH_SPOTIFY_CLIENT_SECRET="" +AURA_AUTH_SPOTIFY_CLIENT_ID= +AURA_AUTH_SPOTIFY_CLIENT_SECRET= # X (Twitter) OAuth App Credentials -AURA_AUTH_X_CLIENT_ID="" -AURA_AUTH_X_CLIENT_SECRET="" +AURA_AUTH_X_CLIENT_ID= +AURA_AUTH_X_CLIENT_SECRET= # Strava OAuth App Credentials -AURA_AUTH_STRAVA_CLIENT_ID="" -AURA_AUTH_STRAVA_CLIENT_SECRET="" +AURA_AUTH_STRAVA_CLIENT_ID= +AURA_AUTH_STRAVA_CLIENT_SECRET= # Atlassian OAuth App Credentials -AURA_AUTH_ATLASSIAN_CLIENT_ID="" -AURA_AUTH_ATLASSIAN_CLIENT_SECRET="" +AURA_AUTH_ATLASSIAN_CLIENT_ID= +AURA_AUTH_ATLASSIAN_CLIENT_SECRET= # Mailchimp OAuth App Credentials -AURA_AUTH_MAILCHIMP_CLIENT_ID="" -AURA_AUTH_MAILCHIMP_CLIENT_SECRET="" +AURA_AUTH_MAILCHIMP_CLIENT_ID= +AURA_AUTH_MAILCHIMP_CLIENT_SECRET= # Pinterest OAuth App Credentials -AURA_AUTH_PINTEREST_CLIENT_ID="" -AURA_AUTH_PINTEREST_CLIENT_SECRET="" +AURA_AUTH_PINTEREST_CLIENT_ID= +AURA_AUTH_PINTEREST_CLIENT_SECRET= # Dropbox OAuth App Credentials -AURA_AUTH_DROPBOX_CLIENT_ID="" -AURA_AUTH_DROPBOX_CLIENT_SECRET="" +AURA_AUTH_DROPBOX_CLIENT_ID= +AURA_AUTH_DROPBOX_CLIENT_SECRET= # Twitch OAuth App Credentials -AURA_AUTH_TWITCH_CLIENT_ID="" -AURA_AUTH_TWITCH_CLIENT_SECRET="" +AURA_AUTH_TWITCH_CLIENT_ID= +AURA_AUTH_TWITCH_CLIENT_SECRET= # Notion OAuth App Credentials -AURA_AUTH_NOTION_CLIENT_ID="" -AURA_AUTH_NOTION_CLIENT_SECRET="" +AURA_AUTH_NOTION_CLIENT_ID= +AURA_AUTH_NOTION_CLIENT_SECRET= # TikTok OAuth App Credentials -AURA_AUTH_TIKTOK_CLIENT_ID="" -AURA_AUTH_TIKTOK_CLIENT_SECRET="" +AURA_AUTH_TIKTOK_CLIENT_ID= +AURA_AUTH_TIKTOK_CLIENT_SECRET= diff --git a/apps/vercel/.env.example b/apps/vercel/.env.example index fce5ea0..e4bc6cf 100644 --- a/apps/vercel/.env.example +++ b/apps/vercel/.env.example @@ -1,11 +1,39 @@ -# Salt for key derivation (e.g., password hashing) -# openssl rand -base64 32 -AURA_AUTH_SALT= - -# Opaque secret used to sign and verify JWT tokens -# openssl rand -base64 32 -AURA_AUTH_SECRET= - +# Opaque salting and peppering secrets for key derivation and hashing +# For example: openssl rand -base64 32 +AURA_AUTH_SALT="" + +# Opaque secret for signing JWT tokens and encrypting data +# For example: openssl rand -base64 32 +AURA_AUTH_SECRET="" + +# The base URL of the authentication server +# For example: http://localhost:4000 +AURA_AUTH_BASE_URL= + +# Trusted Origins for CORS and redirect URI validation (comma-separated) +# For example: http://localhost:3000,http://localhost:4000 +AURA_AUTH_TRUSTED_ORIGINS= + +# Enable debug logging for authentication operations (set to "true", "debug", "on", "yes" or "1" to enable) +AURA_AUTH_DEBUG= + +# Log level for authentication operations (e.g. "error", "warn", "info", "debug") +AURA_AUTH_LOG_LEVEL= + +# PEM-encoded RSA public/private key for signing and encrypting JWT tokens in "sealed" JWT mode (JWT with JWS and JWE) +# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY----- +AURA_AUTH_SIGNING_PUBLIC_KEY= +AURA_AUTH_SIGNING_PRIVATE_KEY= +AURA_AUTH_SIGNING_ALGORITHM= + +AURA_AUTH_ENCRYPTION_PUBLIC_KEY= +AURA_AUTH_ENCRYPTION_PRIVATE_KEY= +AURA_AUTH_ENCRYPTION_ALGORITHM= + +# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE) +AURA_AUTH_PUBLIC_KEY= +AURA_AUTH_PRIVATE_KEY= +AURA_AUTH_ALGORITHM= # Github OAuth App Credentials AURA_AUTH_GITHUB_CLIENT_ID= AURA_AUTH_GITHUB_CLIENT_SECRET= From eb82d5d1e0e7509387c4234713499fa689f20699 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Tue, 28 Apr 2026 11:30:06 -0500 Subject: [PATCH 4/5] docs: add PEM support --- docs/src/content/docs/configuration/env.mdx | 52 +++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/src/content/docs/configuration/env.mdx b/docs/src/content/docs/configuration/env.mdx index 570c863..5ab613a 100644 --- a/docs/src/content/docs/configuration/env.mdx +++ b/docs/src/content/docs/configuration/env.mdx @@ -25,6 +25,7 @@ For more details, read: - [Secure variables](#secure-variables) - [OAuth variables](#oauth-variables) - [Runtime variables](#runtime-variables) +- [PEM variables](#pem-variables) @@ -111,3 +112,54 @@ AURA_AUTH_DEBUG="1" # Built-in logger level AURA_AUTH_LOG_LEVEL="info" ``` + +### PEM Variables + +PEM variables are used to provide PEM-encoded keys and certificates for JWT signing and encryption. They can be set directly as environment variables, or loaded from files using the `_PUBLIC_KEY` and `_PRIVATE_KEY` suffix patterns. + +The PEM variables supported by Aura Auth are related to the `jwt.mode` configuration option which defines if the JWT is signed, encrypted or both. When using PEM keys you can also control the algorithms used to import those keys via two configuration fields: + +- `jwt.importedSigningAlgorithm` — algorithm used to import PEM-formatted signing keys (e.g. `RS256`, `ES256`). +- `jwt.importedEncryptionAlgorithm` — algorithm used to import PEM-formatted encryption keys (e.g. `RSA-OAEP`, `RSA-OAEP-256`). + +These can be set either in the `createAuth` session config or via environment variables `SIGNING_ALGORITHM` / `SIGNING_ALG` and `ENCRYPTION_ALGORITHM` / `ENCRYPTION_ALG` respectively. If not provided a sensible default is chosen (`RS256` for signing imports, `RSA-OAEP-256` for encryption imports). + +| Pattern | Description | +| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `PUBLIC_KEY` | PEM-encoded key used for `sealed` JWT mode (used for both signing and encryption when `sealed`). | +| `PRIVATE_KEY` | PEM-encoded key used for `sealed` JWT mode (used for both signing and encryption when `sealed`). | +| `{KEY}_PUBLIC_KEY` | PEM-encoded public key used for JWT signing or encryption when `jwt.mode` is `signed` or `encrypted` (e.g. `SIGNING_PUBLIC_KEY`). | +| `{KEY}_PRIVATE_KEY` | PEM-encoded private key used for JWT signing or encryption when `jwt.mode` is `signed` or `encrypted` (e.g. `SIGNING_PRIVATE_KEY`). | + + + The loading of PEM variables depends on the `jwt.mode` configuration option. If `jwt.mode` is set to `sealed`, Aura Auth will + look for the `PUBLIC_KEY` and `PRIVATE_KEY` environment variables. If `jwt.mode` is set to `signed` or `encrypted`, Aura Auth + will look for the `{KEY}_PUBLIC_KEY` and `{KEY}_PRIVATE_KEY` environment variables, where `{KEY}` is `SIGNING` or `ENCRYPTION`. + +When importing PEM keys Aura Auth needs to know which algorithm to use for the import step. Set `SIGNING_ALGORITHM`/`SIGNING_ALG` +to control the signing key import (or use `jwt.importedSigningAlgorithm` in the session config). Set `ENCRYPTION_ALGORITHM`/`ENCRYPTION_ALG` +to control the encryption key import (or use `jwt.importedEncryptionAlgorithm` in the session config). Environment variables take precedence +over the session config. + + + +#### Loading PEM variables from files + +PEM variables for `signed` or `encrypted` JWT modes can be loaded from files using the `PUBLIC_KEY` and `PRIVATE_KEY` suffix patterns. For example, if you have a signing key pair stored in `signing_public.pem` and `signing_private.pem`, you can set the following environment variables: + +```bash title=".env" +AURA_AUTH_PUBLIC_KEY='-----BEGIN PUBLIC KEY----- abcd1234 -----END PUBLIC KEY-----' +AURA_AUTH_PRIVATE_KEY='-----BEGIN PRIVATE KEY----- abcd1234 -----END PRIVATE KEY-----' +``` + +PEM variables for `sealed` JWT mode can also be loaded from files using the `_PUBLIC_KEY` and `_PRIVATE_KEY` variable names. For example, if you have a key pair stored in `public.pem` and `private.pem`, you can set the following environment variables: + +```bash title=".env" +# PEM variables for signing JWTs +AURA_AUTH_SIGNING_PUBLIC_KEY='-----BEGIN PUBLIC KEY----- abcd1234 -----END PUBLIC KEY-----' +AURA_AUTH_SIGNING_PRIVATE_KEY='-----BEGIN PRIVATE KEY----- abcd1234 -----END PRIVATE KEY-----' + +# PEM variables for encrypting JWTs +AURA_AUTH_ENCRYPTION_PUBLIC_KEY='-----BEGIN PUBLIC KEY----- abcd1234 -----END PUBLIC KEY-----' +AURA_AUTH_ENCRYPTION_PRIVATE_KEY='-----BEGIN PRIVATE KEY----- abcd1234 -----END PRIVATE KEY-----' +``` From 5edddcc3fe6b2c2e646cf3978befc32068956258 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Tue, 28 Apr 2026 11:46:11 -0500 Subject: [PATCH 5/5] chore: apply coderabbit --- docs/src/content/docs/configuration/env.mdx | 32 ++++++++++----------- packages/core/src/@types/session.ts | 1 - packages/core/test/env.test.ts | 2 +- packages/core/test/presets.ts | 8 ++++++ 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/docs/src/content/docs/configuration/env.mdx b/docs/src/content/docs/configuration/env.mdx index 5ab613a..bab2880 100644 --- a/docs/src/content/docs/configuration/env.mdx +++ b/docs/src/content/docs/configuration/env.mdx @@ -119,28 +119,26 @@ PEM variables are used to provide PEM-encoded keys and certificates for JWT sign The PEM variables supported by Aura Auth are related to the `jwt.mode` configuration option which defines if the JWT is signed, encrypted or both. When using PEM keys you can also control the algorithms used to import those keys via two configuration fields: -- `jwt.importedSigningAlgorithm` — algorithm used to import PEM-formatted signing keys (e.g. `RS256`, `ES256`). -- `jwt.importedEncryptionAlgorithm` — algorithm used to import PEM-formatted encryption keys (e.g. `RSA-OAEP`, `RSA-OAEP-256`). +- `jwt.signingAlgorithm` — algorithm used to import PEM-formatted signing keys (e.g. `RS256`, `ES256`). +- `jwt.keyAlgorithm` — algorithm used to import PEM-formatted encryption keys (e.g. `RSA-OAEP`, `RSA-OAEP-256`). These can be set either in the `createAuth` session config or via environment variables `SIGNING_ALGORITHM` / `SIGNING_ALG` and `ENCRYPTION_ALGORITHM` / `ENCRYPTION_ALG` respectively. If not provided a sensible default is chosen (`RS256` for signing imports, `RSA-OAEP-256` for encryption imports). -| Pattern | Description | -| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `PUBLIC_KEY` | PEM-encoded key used for `sealed` JWT mode (used for both signing and encryption when `sealed`). | -| `PRIVATE_KEY` | PEM-encoded key used for `sealed` JWT mode (used for both signing and encryption when `sealed`). | -| `{KEY}_PUBLIC_KEY` | PEM-encoded public key used for JWT signing or encryption when `jwt.mode` is `signed` or `encrypted` (e.g. `SIGNING_PUBLIC_KEY`). | -| `{KEY}_PRIVATE_KEY` | PEM-encoded private key used for JWT signing or encryption when `jwt.mode` is `signed` or `encrypted` (e.g. `SIGNING_PRIVATE_KEY`). | +| Pattern | Description | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `PUBLIC_KEY` | PEM-encoded public key used when `jwt.mode` is `signed` or `encrypted` (single key pair for one operation). | +| `PRIVATE_KEY` | PEM-encoded private key used when `jwt.mode` is `signed` or `encrypted` (single key pair for one operation). | +| `{KEY}_PUBLIC_KEY` | PEM-encoded public key for `sealed` JWT mode where `{KEY}` is `SIGNING` or `ENCRYPTION` (e.g. `SIGNING_PUBLIC_KEY`). | +| `{KEY}_PRIVATE_KEY` | PEM-encoded private key for `sealed` JWT mode where `{KEY}` is `SIGNING` or `ENCRYPTION` (e.g. `SIGNING_PRIVATE_KEY`). | - The loading of PEM variables depends on the `jwt.mode` configuration option. If `jwt.mode` is set to `sealed`, Aura Auth will - look for the `PUBLIC_KEY` and `PRIVATE_KEY` environment variables. If `jwt.mode` is set to `signed` or `encrypted`, Aura Auth - will look for the `{KEY}_PUBLIC_KEY` and `{KEY}_PRIVATE_KEY` environment variables, where `{KEY}` is `SIGNING` or `ENCRYPTION`. - -When importing PEM keys Aura Auth needs to know which algorithm to use for the import step. Set `SIGNING_ALGORITHM`/`SIGNING_ALG` -to control the signing key import (or use `jwt.importedSigningAlgorithm` in the session config). Set `ENCRYPTION_ALGORITHM`/`ENCRYPTION_ALG` -to control the encryption key import (or use `jwt.importedEncryptionAlgorithm` in the session config). Environment variables take precedence -over the session config. - + The loading of PEM variables depends on the `jwt.mode` configuration option. If `jwt.mode` is set to `signed` or `encrypted`, + Aura Auth will look for the `PUBLIC_KEY` and `PRIVATE_KEY` environment variables. If `jwt.mode` is set to `sealed`, Aura Auth + will look for separate key pairs: `SIGNING_PUBLIC_KEY`/`SIGNING_PRIVATE_KEY` and + `ENCRYPTION_PUBLIC_KEY`/`ENCRYPTION_PRIVATE_KEY`. When importing PEM keys Aura Auth needs to know which algorithm to use for the + import step. Set `SIGNING_ALGORITHM`/`SIGNING_ALG` to control the signing key import (or use `jwt.signingAlgorithm` in the + session config). Set `ENCRYPTION_ALGORITHM`/`ENCRYPTION_ALG` to control the encryption key import (or use `jwt.keyAlgorithm` in + the session config). Environment variables take precedence over the session config. #### Loading PEM variables from files diff --git a/packages/core/src/@types/session.ts b/packages/core/src/@types/session.ts index a353579..05cb25b 100644 --- a/packages/core/src/@types/session.ts +++ b/packages/core/src/@types/session.ts @@ -33,7 +33,6 @@ export interface AsymmetricKeyPairFromEnv { * - string / Uint8Array: used as-is for HMAC (signed) or AES (encrypted) * - CryptoKey: Web Crypto API key, for environments that support it * - CryptoKeyPair: asymmetric signing/encryption (RS256, ES256, EdDSA, RSA-OAEP, etc.) - * - AsymmetricKeyPairFromEnv: asymmetric key pair formatted as PEM strings */ export type SecretKey = string | Uint8Array | CryptoKey | CryptoKeyPair | CryptoSecret diff --git a/packages/core/test/env.test.ts b/packages/core/test/env.test.ts index c8ecbb1..7efb65a 100644 --- a/packages/core/test/env.test.ts +++ b/packages/core/test/env.test.ts @@ -29,7 +29,7 @@ describe("env", () => { expect(env.AURA_AUTH_SECRET).toBe(secret2) }) - test("direct PEM formatted RSA keys", async () => { + test("direct PEM formatted RSA keys", () => { const pem = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtGbid5pLu9wsGut7Fg26 SPBGntzZk6i17MIf2eS++01/7uq0a59yxYa1AvPbO9OdQDngRup7zPUc7dKivwQe diff --git a/packages/core/test/presets.ts b/packages/core/test/presets.ts index 1c742b0..edd3f18 100644 --- a/packages/core/test/presets.ts +++ b/packages/core/test/presets.ts @@ -135,11 +135,19 @@ FwWzwouGrZmIlL4flHagvqx94ObCk+aKxR7H2oPdgb0FDIJu7h7XMrZo3T2jOjfp B+P4zFojgfEO6TszdVGgCkU= -----END PRIVATE KEY-----` +/** + * Test-only RSA key pairs for unit testing PEM import functionality. + * DO NOT use these keys in production - they are publicly visible. + */ export const RS256PEMFormat = { publicKey: RSA256PublicKey, privateKey: RSA256PrivateKey, } +/** + * Test-only RSA key pairs for unit testing PEM import functionality. + * DO NOT use these keys in production - they are publicly visible. + */ export const RSAOAEP256PEMFormat = { publicKey: RSAOAEP256PublicKey, privateKey: RSAOAEP256PrivateKey,