Skip to content

feat(core): support PEM-encoded keys in environment variables#158

Merged
halvaradop merged 5 commits intomasterfrom
feat/support-pem-format
Apr 28, 2026
Merged

feat(core): support PEM-encoded keys in environment variables#158
halvaradop merged 5 commits intomasterfrom
feat/support-pem-format

Conversation

@halvaradop
Copy link
Copy Markdown
Member

@halvaradop halvaradop commented Apr 28, 2026

Description

Adds support for PEM-encoded asymmetric keys via environment variables for JWT operations (signed, encrypted, and sealed modes).

This complements the previously introduced CryptoKeyPair support (#157) by enabling configuration through environment-based key management.

Key Changes

  • Add support for PEM-encoded keys via environment variables
  • Support both:
    • single key pair (signed or encrypted modes)
    • split key pairs (sealed mode: signing + encryption)
  • Update example .env files with:
    • BASE_URL
    • TRUSTED_ORIGINS
    • DEBUG
    • LOG_LEVEL
    • new key variables:
      • AURA_AUTH_PUBLIC_KEY
      • AURA_AUTH_PRIVATE_KEY
      • AURA_AUTH_SIGNING_PUBLIC_KEY
      • AURA_AUTH_SIGNING_PRIVATE_KEY
      • AURA_AUTH_ENCRYPTION_PUBLIC_KEY
      • AURA_AUTH_ENCRYPTION_PRIVATE_KEY

Technical Details

The auth configuration now supports loading asymmetric keys from PEM-encoded environment variables.

Supported Modes

1. Signed or Encrypted (Single Key Pair)

Uses a single public/private key pair:

  • AURA_AUTH_PUBLIC_KEY
  • AURA_AUTH_PRIVATE_KEY

2. Sealed Mode (Split Key Pairs)

Requires two distinct key pairs:

  • Signing keys

    • AURA_AUTH_SIGNING_PUBLIC_KEY
    • AURA_AUTH_SIGNING_PRIVATE_KEY
  • Encryption keys

    • AURA_AUTH_ENCRYPTION_PUBLIC_KEY
    • AURA_AUTH_ENCRYPTION_PRIVATE_KEY

This separation enforces stronger cryptographic isolation between signing and encryption operations.

Usage

Signed or Encrypted Mode

AURA_AUTH_PUBLIC_KEY='-----BEGIN PUBLIC KEY----- abcd1234 -----END PUBLIC KEY-----'
AURA_AUTH_PRIVATE_KEY='-----BEGIN PRIVATE KEY----- abcd1234 -----END PRIVATE KEY-----'

Sealed Mode (Signing + Encryption)

# 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-----'

Related PRs

@halvaradop halvaradop added feature New functionality experimental labels Apr 28, 2026
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
auth Ready Ready Preview, Comment Apr 28, 2026 4:48pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Warning

Rate limit exceeded

@halvaradop has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 43 minutes and 52 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f882f7cf-dbea-43cb-a755-7a84645ec14c

📥 Commits

Reviewing files that changed from the base of the PR and between eb82d5d and 5edddcc.

📒 Files selected for processing (4)
  • docs/src/content/docs/configuration/env.mdx
  • packages/core/src/@types/session.ts
  • packages/core/test/env.test.ts
  • packages/core/test/presets.ts
📝 Walkthrough

Walkthrough

Adds support for PEM-formatted asymmetric key pairs supplied via environment variables, imports PEM keys into WebCrypto-compatible keys, introduces new type/interface and error type, expands type guards, updates JOSE secret resolution to handle PEM inputs, and extends tests and .env examples and docs to document PEM variables.

Changes

Cohort / File(s) Summary
Type defs & guards
packages/core/src/@types/session.ts, packages/core/src/shared/assert.ts
Added AsymmetricKeyPairFromEnv interface; wrapped JWTConfig with Prettify; added PEM-related type guards (isPEMFormattedKey, isPEMFormattedKeyPairFromEnv, isJWTPEMFormattedKeyPair) and adjusted isSealedMode narrowing.
JOSE initialization & secret resolution
packages/core/src/jose.ts
Introduced getSecretKey helper and extended getSecrets to accept PEM env key-pairs, detect combined vs separate PEM inputs, enforce mode compatibility via AuthJoseInitializationError, derive/import PEM keys (via importPEMKeyPair), and parameterize crypto-secret/crypto-key paths by resolved secret.
Crypto helpers & errors
packages/core/src/shared/crypto.ts, packages/core/src/shared/errors.ts
Added importPEMKeyPair to import SPKI/PKCS#8 PEM into CryptoKeyPair; added AuthJoseInitializationError class for JOSE init failures.
Tests & presets
packages/core/test/jose.test.ts, packages/core/test/env.test.ts, packages/core/test/presets.ts
Added PEM RSA key presets and tests exercising PEM env loading, sign/verify, encrypt/decrypt flows, and expected failure cases for incompatible/misconfigured modes.
Docs & env examples
docs/src/content/docs/configuration/env.mdx, apps/*/.env.example (many apps)
Documented “PEM Variables” behavior and added PEM-related environment placeholders and auth config variables across .env.example files (signing/encryption public/private keys and algorithm settings).

Sequence Diagram

sequenceDiagram
    participant Env as Environment
    participant Jose as createJoseInstance / getSecrets
    participant Guard as PEM Type Guards
    participant Importer as importPEMKeyPair
    participant Crypto as WebCrypto (CryptoKeyPair)
    participant Session as SessionConfig

    Env->>Jose: init (secret/session/config)
    Jose->>Guard: inspect secret inputs (strings/objects/env)
    Guard-->>Jose: detect PEM combined / separate keys
    Jose->>Importer: import PEM (public, private, algorithm)
    Importer->>Crypto: importSPKI / importPKCS8
    Crypto-->>Importer: CryptoKeyPair
    Importer-->>Jose: return imported keys
    Jose->>Jose: derive jws/jwe secrets (using session/importedAlgorithm)
    Jose-->>Env: JOSE initialized (jwsSecret, jweSecret, jwtSecret)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

documentation

Poem

🐇 I nibble PEM strings from the env at dawn,
I flip PKCS8 and SPKI on the lawn,
Keys imported, algorithms align,
JWTs hop out secure and fine —
A rabbit’s clap for crypto spun! 🎩✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: adding support for PEM-encoded keys in environment variables, which is the primary focus across core types, helpers, tests, documentation, and environment examples.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/support-pem-format

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/`@types/session.ts:
- Around line 142-152: The importedAlgorithm field is currently a top-level
union (JWTSigningAlgorithm | JWTKeyAlgorithm) and is permitted for all JWT
modes; change the session type to a discriminated union keyed by mode so
importedAlgorithm is only present for mode: "signed" (typed as
JWTSigningAlgorithm) and mode: "encrypted" (typed as JWTKeyAlgorithm), and
remove it from mode: "sealed"; update the interface/type that defines
importedAlgorithm (search for importedAlgorithm and the session/options type) to
implement these mode-specific variants so invalid combinations like mode:
"signed" with "RSA-OAEP-256" are rejected at compile time.

In `@packages/core/src/jose.ts`:
- Around line 128-130: The algorithm selection currently prefers environment
variables over the per-session override; change the precedence so
importedAlgorithm wins by assigning algorithm using importedAlgorithm first,
then getEnv("ALGORITHM"), then getEnv("ALG"), then the default "RS256", and keep
using that algorithm when calling importPKCS8(privateKey, algorithm, ...) and
importSPKI(publicKey, algorithm, ...).
- Around line 140-143: The jwtSecret currently assigns single CryptoKey values
to sign and encrypt (sign: importedPrivateKey, encrypt: importedPublicKey),
which prevents the secret processor from splitting keys for JWS/JWE round-trips;
change jwtSecret so both sign and encrypt are full CryptoKeyPair-like objects:
wrap sign with an object containing the privateKey (importedPrivateKey) and its
corresponding publicKey (importedPublicKey), and wrap encrypt with an object
containing the publicKey (importedPublicKey) and its corresponding privateKey
(importedPrivateKey) so the secret processor can pick the correct key for
sign/verify and encrypt/decrypt operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: caa4d608-628e-4080-be82-1e454e77e58b

📥 Commits

Reviewing files that changed from the base of the PR and between 32df89c and 5a4b8e0.

📒 Files selected for processing (5)
  • packages/core/src/@types/session.ts
  • packages/core/src/jose.ts
  • packages/core/src/shared/assert.ts
  • packages/core/test/env.test.ts
  • packages/core/test/jose.test.ts

Comment thread packages/core/src/@types/session.ts Outdated
Comment thread packages/core/src/jose.ts Outdated
Comment thread packages/core/src/jose.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (25)
apps/vercel/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

Fix typo in PEM example format.

Same issue as in apps/supabase/.env.example: extra space before closing dashes in the example.

📝 Suggested fix
 # 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-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/vercel/.env.example` around lines 23 - 24, The PEM example in the env
example currently has an extra space before the closing dashes (e.g. "-----BEGIN
PUBLIC KEY -----" / "-----END PUBLIC KEY -----"); update the example string used
for the "PEM-encoded RSA public/private key for signing and encrypting JWT
tokens" entry so the markers are correctly formatted without the extra space
("-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----"), matching the
fixed format used in apps/supabase/.env.example.
apps/supabase/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

Fix typo in PEM example format.

The example shows -----BEGIN PUBLIC KEY ----- with an extra space before the closing dashes. This could mislead users.

📝 Suggested fix
 # 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-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/supabase/.env.example` around lines 23 - 24, The PEM example in the
.env.example contains extra spaces inside the BEGIN/END markers; update the
literal strings "-----BEGIN PUBLIC KEY -----" and "-----END PUBLIC KEY -----" to
remove the extra space so they read "-----BEGIN PUBLIC KEY-----" and "-----END
PUBLIC KEY-----", and keep the newline escape form as "-----BEGIN PUBLIC
KEY-----\n...\n-----END PUBLIC KEY-----" so the example shows the correct PEM
marker format.
apps/supabase/.env.example-33-36 (1)

33-36: ⚠️ Potential issue | 🟡 Minor

Fix typo and add missing newline.

"PEM-encode" should be "PEM-encoded". Also, there's a missing blank line between the PEM variables section and the GitHub OAuth section for consistency with other sections.

📝 Suggested fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded 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
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/supabase/.env.example` around lines 33 - 36, Fix the typo in the comment
header and add the missing blank line after the PEM variables: change
"PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode
(JWT with JWS or JWE)" to "PEM-encoded RSA public/private key either in "signed"
or "encrypted" JWT mode (JWT with JWS or JWE)" and insert a single empty line
after the AURA_AUTH_PUBLIC_KEY, AURA_AUTH_PRIVATE_KEY, and AURA_AUTH_ALGORITHM
entries to separate this PEM section from the following GitHub OAuth section.
apps/vercel/.env.example-33-36 (1)

33-36: ⚠️ Potential issue | 🟡 Minor

Fix typo and add missing newline.

Same issues as apps/supabase/.env.example: "PEM-encode" should be "PEM-encoded", and missing blank line before OAuth section.

📝 Suggested fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded 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
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/vercel/.env.example` around lines 33 - 36, Fix the typo in the
environment comment by changing "PEM-encode" to "PEM-encoded" and add a missing
blank line before the OAuth section; specifically update the comment line that
precedes AURA_AUTH_PUBLIC_KEY, AURA_AUTH_PRIVATE_KEY, and AURA_AUTH_ALGORITHM to
read "PEM-encoded RSA public/private key either in 'signed' or 'encrypted' JWT
mode (JWT with JWS or JWE)" and insert a blank line separating this block from
the following OAuth-related env vars/section.
apps/deno/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/deno/.env.example` at line 24, The PEM header example string in the .env
example uses incorrect spacing: update the example line containing "-----BEGIN
PUBLIC KEY -----" to the standard PEM header "-----BEGIN PUBLIC KEY-----" (and
similarly ensure the footer example, if present, is "-----END PUBLIC KEY-----")
so the provided example matches standard PEM formatting.
apps/elysia/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/elysia/.env.example` at line 33, Replace the inconsistent phrase
"PEM-encode" with "PEM-encoded" in the comment that reads "PEM-encode RSA
public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or
JWE)"; update that string to "PEM-encoded RSA public/private key either in
"signed" or "encrypted" JWT mode (JWT with JWS or JWE)" so it matches the
terminology used elsewhere like "PEM-encoded".
apps/oak/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/oak/.env.example` at line 33, The README/environment example uses
inconsistent terminology: change the phrase "PEM-encode" to "PEM-encoded" so it
matches the usage on line 23; update the text that currently reads "PEM-encode
RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS
or JWE)" to use "PEM-encoded" instead of "PEM-encode" (search for the token
"PEM-encode" to locate the occurrence).
apps/oak/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/oak/.env.example` at line 24, Update the PEM header/footer example in
the .env.example so it uses the standard PEM formatting without spaces: replace
the incorrect "-----BEGIN PUBLIC KEY -----" and corresponding footer with
"-----BEGIN PUBLIC KEY-----" (and ensure any footer uses "-----END PUBLIC
KEY-----") in the example string shown in apps/oak/.env.example to remove the
extra space before the closing dashes.
apps/elysia/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/elysia/.env.example` at line 24, The PEM header/example in the
.env.example contains inconsistent spacing ("-----BEGIN PUBLIC KEY -----" and
"-----END PUBLIC KEY -----"); update those example lines to the standard PEM
tokens by removing the extra space so they read "-----BEGIN PUBLIC KEY-----" and
"-----END PUBLIC KEY-----" (ensure both BEGIN and END examples are fixed).
apps/deno/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/deno/.env.example` at line 33, Update the inconsistent wording in the
env comment that currently reads "# PEM-encode RSA public/private key either in
"signed" or "encrypted" JWT mode (JWT with JWS or JWE)"; change "PEM-encode" to
"PEM-encoded" so it matches the terminology used elsewhere (e.g., the earlier
"PEM-encoded" instance).
apps/astro/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/astro/.env.example` at line 24, Update the PEM example headers in the
.env example to use standard PEM formatting: replace the incorrect "-----BEGIN
PUBLIC KEY -----" (with a space before the closing dashes) with "-----BEGIN
PUBLIC KEY-----" and likewise ensure the footer reads "-----END PUBLIC KEY-----"
(no extra spaces); locate the example block that currently shows "# For example:
-----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY -----" and correct both
header/footer strings and any identical variants so the PEM example matches
standard format.
apps/astro/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/astro/.env.example` at line 33, Update the wording in the environment
example comment that currently reads "PEM-encode RSA public/private key either
in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)" to use the consistent
term "PEM-encoded" (matching the usage on line 23); replace "PEM-encode" with
"PEM-encoded" so the phrase becomes "PEM-encoded RSA public/private key either
in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)".
apps/nextjs/pages-router/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/nextjs/pages-router/.env.example` at line 24, Replace the incorrectly
spaced PEM header example "-----BEGIN PUBLIC KEY -----" with the standard format
"-----BEGIN PUBLIC KEY-----" (and likewise ensure the footer uses "-----END
PUBLIC KEY-----" if present) so the .env example uses valid PEM delimiters;
locate the example string in the .env.example and update the header/footer
delimiters accordingly.
apps/react-router/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/react-router/.env.example` at line 33, The comment points out
inconsistent terminology: replace the phrase "PEM-encode" used in the
explanatory string for JWT keys with the correct and consistent term
"PEM-encoded" (matching the usage on line 23); update the string that currently
reads 'PEM-encode RSA public/private key either in "signed" or "encrypted" JWT
mode (JWT with JWS or JWE)' so it uses "PEM-encoded" instead of "PEM-encode".
apps/hono/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/hono/.env.example` at line 33, The comment uses inconsistent
terminology: change the phrase "PEM-encode" to "PEM-encoded" in the commented
line that currently reads 'PEM-encode RSA public/private key either in "signed"
or "encrypted" JWT mode (JWT with JWS or JWE)' so it matches the earlier usage
"PEM-encoded"; update that exact comment string to use "PEM-encoded".
apps/nextjs/pages-router/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/nextjs/pages-router/.env.example` at line 33, The comment uses
inconsistent terminology: replace the phrase "PEM-encode RSA public/private key
either in \"signed\" or \"encrypted\" JWT mode (JWT with JWS or JWE)" with
"PEM-encoded RSA public/private key either in \"signed\" or \"encrypted\" JWT
mode (JWT with JWS or JWE)" so it matches the "PEM-encoded" wording used
elsewhere (e.g., line 23).
apps/react-router/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/react-router/.env.example` at line 24, The PEM header example string
currently has an extra space ("-----BEGIN PUBLIC KEY -----"); update the example
to the correct standard PEM header "-----BEGIN PUBLIC KEY-----" (and likewise
ensure the footer uses "-----END PUBLIC KEY-----" if present) in the
apps/react-router .env.example so the example matches standard PEM formatting.
apps/hono/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/hono/.env.example` at line 24, Update the PEM header/footer example so
it uses standard PEM formatting without spaces before the closing dashes:
replace the example string "-----BEGIN PUBLIC KEY -----" with "-----BEGIN PUBLIC
KEY-----" (and ensure the corresponding footer uses "-----END PUBLIC KEY-----"
if present) so the .env example shows correct PEM headers/footers.
apps/nextjs/app-router/.env.example-24-24 (1)

24-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM header example formatting.

The example PEM header has inconsistent spacing. "-----BEGIN PUBLIC KEY -----" includes a space before the closing dashes, but standard PEM format should be "-----BEGIN PUBLIC KEY-----" without spaces.

📝 Proposed fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/nextjs/app-router/.env.example` at line 24, The PEM header example
currently has an extra space ("-----BEGIN PUBLIC KEY -----") which is
nonstandard; update the example string to the correct PEM header/footer format
without spaces ("-----BEGIN PUBLIC KEY-----" and correspondingly "-----END
PUBLIC KEY-----") so the .env.example shows the valid PEM block format used by
functions that parse public keys.
apps/nextjs/app-router/.env.example-33-33 (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Correct the inconsistent terminology.

Line 33 uses "PEM-encode" while line 23 correctly uses "PEM-encoded". The terminology should be consistent.

📝 Proposed fix
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/nextjs/app-router/.env.example` at line 33, Update the wording in the
.env example so terminology matches line 23: change the phrase "PEM-encode RSA
public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or
JWE)" to use "PEM-encoded" instead of "PEM-encode" so the file consistently uses
"PEM-encoded"; locate this string in apps/nextjs/app-router/.env.example and
replace accordingly.
apps/tanstack-start/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

Correct PEM example formatting and wording.

Line 24 shows an invalid PEM header format (extra space before trailing dashes), and Line 33 has a wording typo (PEM-encode).

Suggested doc fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
@@
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)

Also applies to: 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/tanstack-start/.env.example` around lines 23 - 24, Fix the PEM example
and wording in the env example: correct the PEM header/footer to use the
standard "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" (no extra
spaces inside the dashes) in the JWT PEM example and update the typo
"PEM-encode" to "PEM-encoded" so the description reads "PEM-encoded RSA
public/private key for signing and encrypting JWT tokens" to match standard PEM
formatting and clear wording.
apps/cloudflare/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

PEM sample string is malformed and comment has a typo.

At Line 24, the PEM header contains an extra space and is not copy/paste-safe. At Line 33, use PEM-encoded for consistency and clarity.

Suggested doc fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
@@
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)

Also applies to: 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cloudflare/.env.example` around lines 23 - 24, Fix the malformed PEM
sample and typo in the comments: remove the extra space in the PEM header/footer
sample so the example reads "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC
KEY-----" instead of "-----BEGIN PUBLIC KEY -----", and replace the inconsistent
"PEM-encoded" wording at the other comment with the exact term "PEM-encoded" for
consistency (update the comment that currently mentions PEM wording around the
JWT sealing description).
apps/express/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

Fix repeated PEM example typo in env template.

The PEM sample at Line 24 has an extra space in the header and can fail if copied; Line 33 should read PEM-encoded.

Suggested doc fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
@@
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)

Also applies to: 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/.env.example` around lines 23 - 24, Fix the PEM example typos in
the env template: remove the extraneous space in the PEM headers/footers so the
example reads "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" (and
similarly for PRIVATE KEY lines) and correct the descriptor from any incorrect
variation to "PEM-encoded" where it appears; update all occurrences of the
sample PEM and the descriptor to match these exact strings so copies work
without failing.
apps/bun/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

Fix PEM example/header typo in docs block.

The example PEM header at Line 24 has an extra space (PUBLIC KEY -----), which makes it invalid if copied verbatim. Also, Line 33 should read PEM-encoded, not PEM-encode.

Suggested doc fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
@@
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)

Also applies to: 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/bun/.env.example` around lines 23 - 24, Fix the PEM example header and
the typo in the doc text: replace the malformed example header string
"-----BEGIN PUBLIC KEY -----" (with the extra space) with the correct
"-----BEGIN PUBLIC KEY-----" and ensure the matching footer uses "-----END
PUBLIC KEY-----"; also correct the wording "PEM-encode" to "PEM-encoded" in the
same doc block so the description reads "PEM-encoded RSA public/private key".
These changes target the PEM example text in the env example block (the PEM
header/footer strings and the descriptive phrase "PEM-encode").
apps/nuxt/.env.example-23-24 (1)

23-24: ⚠️ Potential issue | 🟡 Minor

Make PEM example copy/paste-safe.

Given core PEM validation, the Line 24 example should be syntactically valid PEM (-----BEGIN PUBLIC KEY-----). Also fix wording on Line 33 (PEM-encoded).

Suggested doc fix
-# For example: -----BEGIN PUBLIC KEY -----\n...\n-----END PUBLIC KEY-----
+# For example: -----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----
@@
-# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)
+# PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)

Also applies to: 33-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/nuxt/.env.example` around lines 23 - 24, Update the example PEM so it is
valid and copy/paste-safe by using the correct header/footer text with no extra
spaces (use "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" and show
literal newline escapes if needed), and make the documentation wording
consistent by changing the phrase at the later mention to "PEM-encoded" so both
occurrences use the correct PEM header/footer syntax and the same wording.
🧹 Nitpick comments (5)
packages/core/test/env.test.ts (1)

32-44: Test is marked async but doesn't use await.

This test function is marked as async but doesn't contain any await expressions. The PEM string is hardcoded, so async is unnecessary here. This is a minor inconsistency.

♻️ Suggested fix
-    test("direct PEM formatted RSA keys", async () => {
+    test("direct PEM formatted RSA keys", () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/test/env.test.ts` around lines 32 - 44, The test "direct PEM
formatted RSA keys" is marked async but contains no await; remove the
unnecessary async keyword from the test callback to avoid misleading async
usage—locate the test function named test("direct PEM formatted RSA keys", ...)
in env.test.ts and change the callback from async () => { ... } to () => { ... }
(no other changes to the PEM string, vi.stubEnv call, or expect assertion).
packages/core/test/presets.ts (1)

60-68: Add comment clarifying these are test-only keys.

Static analysis tools flagged these as exposed private keys. While this is a false positive (these are test fixtures), adding a clear comment would help future maintainers and suppress alerts.

♻️ Suggested comment addition
+/**
+ * Test-only RSA key pairs for unit testing PEM import functionality.
+ * DO NOT use these keys in production - they are publicly visible.
+ */
 const RSA256PublicKey = `-----BEGIN PUBLIC KEY-----
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/test/presets.ts` around lines 60 - 68, Add a clear, single-line
comment immediately above the RSA256PublicKey constant (the test fixture PEM
string) stating that these are test-only/public-only keys and not secrets (e.g.,
"Test fixture — non-secret public key used only in tests") so static analysis
and future maintainers understand this is safe to keep in source; update the
comment near the RSA256PublicKey declaration and, if your tooling supports it,
include a short note like "DO NOT USE IN PRODUCTION" to make intent explicit.
packages/core/src/shared/errors.ts (1)

94-104: Missing type guard for new error class.

Other error classes in this file have corresponding type guard functions (e.g., isAuthInternalError, isAuthClientError). Consider adding isAuthJoseInitializationError for consistency.

Additionally, isAuthErrorWithCode (line 134) should include the new error class since it has a code property.

♻️ Proposed additions
 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 isAuthJoseInitializationError = (error: unknown): error is AuthJoseInitializationError => {
+    return error instanceof AuthJoseInitializationError
+}

And update isAuthErrorWithCode:

 export const isAuthErrorWithCode = (error: unknown): error is { code: string; message: string } => {
-    return isAuthInternalError(error) || isAuthSecurityError(error) || isAuthClientError(error) || isAuthValidationError(error)
+    return isAuthInternalError(error) || isAuthSecurityError(error) || isAuthClientError(error) || isAuthValidationError(error) || isAuthJoseInitializationError(error)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/shared/errors.ts` around lines 94 - 104, Add a type guard
for the new AuthJoseInitializationError class and include the class in the
isAuthErrorWithCode check: implement a function
isAuthJoseInitializationError(value: unknown): value is
AuthJoseInitializationError that returns true when value is an object with name
"AuthJoseInitializationError" (or instanceof AuthJoseInitializationError) and
has a string code, and then update the existing isAuthErrorWithCode predicate to
also recognize AuthJoseInitializationError alongside the other error classes so
the new class is treated as an error that carries a code.
docs/src/content/docs/configuration/env.mdx (1)

146-165: Section headers are inconsistent with content.

The section says "Loading PEM variables from files" but the examples show setting environment variables directly with PEM content, not loading from files. Consider clarifying that these are inline PEM values or showing actual file-loading syntax if that's supported.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/content/docs/configuration/env.mdx` around lines 146 - 165, The
header "Loading PEM variables from files" doesn't match the examples which show
inline PEM values; update the docs to either (A) rename the section to
"Specifying PEM variables inline" and keep the current examples for
AURA_AUTH_PUBLIC_KEY / AURA_AUTH_PRIVATE_KEY and the AURA_AUTH_SIGNING_* /
AURA_AUTH_ENCRYPTION_* variables, or (B) show the actual file-loading approach
supported by the app (for example using *_FILE or a shell command to read
public.pem/private.pem into env vars) and replace the inline PEM examples with
the file-based usage for the same environment variable names.
packages/core/src/shared/crypto.ts (1)

146-153: Consider removing extractable: true or setting it to false for the private key.

Both keys are imported with extractable: true, but there are no key export operations anywhere in the codebase. Since the keys are only used for signing and encryption operations in createJWT, createJWS, and createJWE, the private key should not be extractable. Set extractable: false for the private key to follow the principle of least privilege.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/shared/crypto.ts` around lines 146 - 153, The
importPEMKeyPair function currently imports both keys with extractable: true;
change the private key import to non-extractable to follow least
privilege—update the importPKCS8 call inside importPEMKeyPair to use {
extractable: false } for the privateKey while leaving importSPKI for the
publicKey as-is (or true), ensuring existing consumers like createJWT,
createJWS, and createJWE continue to operate without requiring key export
capability.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/src/content/docs/configuration/env.mdx`:
- Around line 127-133: The table entries for PUBLIC_KEY/PRIVATE_KEY and
{KEY}_PUBLIC_KEY/{KEY}_PRIVATE_KEY are inverted; update the docs so PUBLIC_KEY
and PRIVATE_KEY are described as the PEM pair used when jwt.mode is "signed" or
"encrypted", and describe the per-key pairs (e.g.
SIGNING_PUBLIC_KEY/SIGNING_PRIVATE_KEY and
ENCRYPTION_PUBLIC_KEY/ENCRYPTION_PRIVATE_KEY) as the keys used in "sealed" mode;
reference the jwt.mode naming and the mapping in packages/core/src/jose.ts
(symbols: PUBLIC_KEY, PRIVATE_KEY, SIGNING_PUBLIC_KEY, SIGNING_PRIVATE_KEY,
ENCRYPTION_PUBLIC_KEY, ENCRYPTION_PRIVATE_KEY) when making the swap.
- Around line 120-125: Update the docs to use the real config fields: replace
references to jwt.importedSigningAlgorithm with jwt.signingAlgorithm, and
replace jwt.importedEncryptionAlgorithm with jwt.encryptionAlgorithm; also
mention jwt.keyAlgorithm (key management algorithm) and clarify that encryption
requires both jwt.keyAlgorithm and jwt.encryptionAlgorithm. Adjust the
environment variable mapping text to show SIGNING_ALGORITHM / SIGNING_ALG ->
jwt.signingAlgorithm, ENCRYPTION_ALGORITHM / ENCRYPTION_ALG ->
jwt.encryptionAlgorithm, and add KEY_ALGORITHM / KEY_ALG -> jwt.keyAlgorithm so
the docs match the actual config symbols.
- Around line 134-144: The callout text is inverted: it claims
PUBLIC_KEY/PRIVATE_KEY are used for jwt.mode == sealed whereas the code uses
them for signed/encrypted and uses {KEY}_PUBLIC_KEY/{KEY}_PRIVATE_KEY for
sealed; update the callout to match the implementation by swapping the
descriptions so that when jwt.mode is sealed Aura Auth looks for
{KEY}_PUBLIC_KEY and {KEY}_PRIVATE_KEY (SIGNING/ENCRYPTION) and when jwt.mode is
signed or encrypted it looks for PUBLIC_KEY and PRIVATE_KEY; also ensure the
guidance about SIGNING_ALGORITHM / SIGNING_ALG and ENCRYPTION_ALGORITHM /
ENCRYPTION_ALG (and jwt.importedSigningAlgorithm /
jwt.importedEncryptionAlgorithm) still notes that environment variables take
precedence over session config.

In `@packages/core/src/`@types/session.ts:
- Around line 30-38: The JSDoc wrongly documents AsymmetricKeyPairFromEnv as
part of the SecretKey union; update the comment above the SecretKey type so it
no longer lists AsymmetricKeyPairFromEnv and instead only describes the actual
union members (string, Uint8Array, CryptoKey, CryptoKeyPair, CryptoSecret), and
add a short note that PEM key pairs (AsymmetricKeyPairFromEnv) must be converted
using importPEMKeyPair (see jose.ts handling) before use; modify the comment
near the SecretKey type definition to match the actual type.

---

Minor comments:
In `@apps/astro/.env.example`:
- Line 24: Update the PEM example headers in the .env example to use standard
PEM formatting: replace the incorrect "-----BEGIN PUBLIC KEY -----" (with a
space before the closing dashes) with "-----BEGIN PUBLIC KEY-----" and likewise
ensure the footer reads "-----END PUBLIC KEY-----" (no extra spaces); locate the
example block that currently shows "# For example: -----BEGIN PUBLIC KEY
-----\n...\n-----END PUBLIC KEY -----" and correct both header/footer strings
and any identical variants so the PEM example matches standard format.
- Line 33: Update the wording in the environment example comment that currently
reads "PEM-encode RSA public/private key either in "signed" or "encrypted" JWT
mode (JWT with JWS or JWE)" to use the consistent term "PEM-encoded" (matching
the usage on line 23); replace "PEM-encode" with "PEM-encoded" so the phrase
becomes "PEM-encoded RSA public/private key either in "signed" or "encrypted"
JWT mode (JWT with JWS or JWE)".

In `@apps/bun/.env.example`:
- Around line 23-24: Fix the PEM example header and the typo in the doc text:
replace the malformed example header string "-----BEGIN PUBLIC KEY -----" (with
the extra space) with the correct "-----BEGIN PUBLIC KEY-----" and ensure the
matching footer uses "-----END PUBLIC KEY-----"; also correct the wording
"PEM-encode" to "PEM-encoded" in the same doc block so the description reads
"PEM-encoded RSA public/private key". These changes target the PEM example text
in the env example block (the PEM header/footer strings and the descriptive
phrase "PEM-encode").

In `@apps/cloudflare/.env.example`:
- Around line 23-24: Fix the malformed PEM sample and typo in the comments:
remove the extra space in the PEM header/footer sample so the example reads
"-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----" instead of
"-----BEGIN PUBLIC KEY -----", and replace the inconsistent "PEM-encoded"
wording at the other comment with the exact term "PEM-encoded" for consistency
(update the comment that currently mentions PEM wording around the JWT sealing
description).

In `@apps/deno/.env.example`:
- Line 24: The PEM header example string in the .env example uses incorrect
spacing: update the example line containing "-----BEGIN PUBLIC KEY -----" to the
standard PEM header "-----BEGIN PUBLIC KEY-----" (and similarly ensure the
footer example, if present, is "-----END PUBLIC KEY-----") so the provided
example matches standard PEM formatting.
- Line 33: Update the inconsistent wording in the env comment that currently
reads "# PEM-encode RSA public/private key either in "signed" or "encrypted" JWT
mode (JWT with JWS or JWE)"; change "PEM-encode" to "PEM-encoded" so it matches
the terminology used elsewhere (e.g., the earlier "PEM-encoded" instance).

In `@apps/elysia/.env.example`:
- Line 33: Replace the inconsistent phrase "PEM-encode" with "PEM-encoded" in
the comment that reads "PEM-encode RSA public/private key either in "signed" or
"encrypted" JWT mode (JWT with JWS or JWE)"; update that string to "PEM-encoded
RSA public/private key either in "signed" or "encrypted" JWT mode (JWT with JWS
or JWE)" so it matches the terminology used elsewhere like "PEM-encoded".
- Line 24: The PEM header/example in the .env.example contains inconsistent
spacing ("-----BEGIN PUBLIC KEY -----" and "-----END PUBLIC KEY -----"); update
those example lines to the standard PEM tokens by removing the extra space so
they read "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" (ensure
both BEGIN and END examples are fixed).

In `@apps/express/.env.example`:
- Around line 23-24: Fix the PEM example typos in the env template: remove the
extraneous space in the PEM headers/footers so the example reads "-----BEGIN
PUBLIC KEY-----" and "-----END PUBLIC KEY-----" (and similarly for PRIVATE KEY
lines) and correct the descriptor from any incorrect variation to "PEM-encoded"
where it appears; update all occurrences of the sample PEM and the descriptor to
match these exact strings so copies work without failing.

In `@apps/hono/.env.example`:
- Line 33: The comment uses inconsistent terminology: change the phrase
"PEM-encode" to "PEM-encoded" in the commented line that currently reads
'PEM-encode RSA public/private key either in "signed" or "encrypted" JWT mode
(JWT with JWS or JWE)' so it matches the earlier usage "PEM-encoded"; update
that exact comment string to use "PEM-encoded".
- Line 24: Update the PEM header/footer example so it uses standard PEM
formatting without spaces before the closing dashes: replace the example string
"-----BEGIN PUBLIC KEY -----" with "-----BEGIN PUBLIC KEY-----" (and ensure the
corresponding footer uses "-----END PUBLIC KEY-----" if present) so the .env
example shows correct PEM headers/footers.

In `@apps/nextjs/app-router/.env.example`:
- Line 24: The PEM header example currently has an extra space ("-----BEGIN
PUBLIC KEY -----") which is nonstandard; update the example string to the
correct PEM header/footer format without spaces ("-----BEGIN PUBLIC KEY-----"
and correspondingly "-----END PUBLIC KEY-----") so the .env.example shows the
valid PEM block format used by functions that parse public keys.
- Line 33: Update the wording in the .env example so terminology matches line
23: change the phrase "PEM-encode RSA public/private key either in "signed" or
"encrypted" JWT mode (JWT with JWS or JWE)" to use "PEM-encoded" instead of
"PEM-encode" so the file consistently uses "PEM-encoded"; locate this string in
apps/nextjs/app-router/.env.example and replace accordingly.

In `@apps/nextjs/pages-router/.env.example`:
- Line 24: Replace the incorrectly spaced PEM header example "-----BEGIN PUBLIC
KEY -----" with the standard format "-----BEGIN PUBLIC KEY-----" (and likewise
ensure the footer uses "-----END PUBLIC KEY-----" if present) so the .env
example uses valid PEM delimiters; locate the example string in the .env.example
and update the header/footer delimiters accordingly.
- Line 33: The comment uses inconsistent terminology: replace the phrase
"PEM-encode RSA public/private key either in \"signed\" or \"encrypted\" JWT
mode (JWT with JWS or JWE)" with "PEM-encoded RSA public/private key either in
\"signed\" or \"encrypted\" JWT mode (JWT with JWS or JWE)" so it matches the
"PEM-encoded" wording used elsewhere (e.g., line 23).

In `@apps/nuxt/.env.example`:
- Around line 23-24: Update the example PEM so it is valid and copy/paste-safe
by using the correct header/footer text with no extra spaces (use "-----BEGIN
PUBLIC KEY-----" and "-----END PUBLIC KEY-----" and show literal newline escapes
if needed), and make the documentation wording consistent by changing the phrase
at the later mention to "PEM-encoded" so both occurrences use the correct PEM
header/footer syntax and the same wording.

In `@apps/oak/.env.example`:
- Line 33: The README/environment example uses inconsistent terminology: change
the phrase "PEM-encode" to "PEM-encoded" so it matches the usage on line 23;
update the text that currently reads "PEM-encode RSA public/private key either
in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)" to use "PEM-encoded"
instead of "PEM-encode" (search for the token "PEM-encode" to locate the
occurrence).
- Line 24: Update the PEM header/footer example in the .env.example so it uses
the standard PEM formatting without spaces: replace the incorrect "-----BEGIN
PUBLIC KEY -----" and corresponding footer with "-----BEGIN PUBLIC KEY-----"
(and ensure any footer uses "-----END PUBLIC KEY-----") in the example string
shown in apps/oak/.env.example to remove the extra space before the closing
dashes.

In `@apps/react-router/.env.example`:
- Line 33: The comment points out inconsistent terminology: replace the phrase
"PEM-encode" used in the explanatory string for JWT keys with the correct and
consistent term "PEM-encoded" (matching the usage on line 23); update the string
that currently reads 'PEM-encode RSA public/private key either in "signed" or
"encrypted" JWT mode (JWT with JWS or JWE)' so it uses "PEM-encoded" instead of
"PEM-encode".
- Line 24: The PEM header example string currently has an extra space
("-----BEGIN PUBLIC KEY -----"); update the example to the correct standard PEM
header "-----BEGIN PUBLIC KEY-----" (and likewise ensure the footer uses
"-----END PUBLIC KEY-----" if present) in the apps/react-router .env.example so
the example matches standard PEM formatting.

In `@apps/supabase/.env.example`:
- Around line 23-24: The PEM example in the .env.example contains extra spaces
inside the BEGIN/END markers; update the literal strings "-----BEGIN PUBLIC KEY
-----" and "-----END PUBLIC KEY -----" to remove the extra space so they read
"-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----", and keep the
newline escape form as "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC
KEY-----" so the example shows the correct PEM marker format.
- Around line 33-36: Fix the typo in the comment header and add the missing
blank line after the PEM variables: change "PEM-encode RSA public/private key
either in "signed" or "encrypted" JWT mode (JWT with JWS or JWE)" to
"PEM-encoded RSA public/private key either in "signed" or "encrypted" JWT mode
(JWT with JWS or JWE)" and insert a single empty line after the
AURA_AUTH_PUBLIC_KEY, AURA_AUTH_PRIVATE_KEY, and AURA_AUTH_ALGORITHM entries to
separate this PEM section from the following GitHub OAuth section.

In `@apps/tanstack-start/.env.example`:
- Around line 23-24: Fix the PEM example and wording in the env example: correct
the PEM header/footer to use the standard "-----BEGIN PUBLIC KEY-----" and
"-----END PUBLIC KEY-----" (no extra spaces inside the dashes) in the JWT PEM
example and update the typo "PEM-encode" to "PEM-encoded" so the description
reads "PEM-encoded RSA public/private key for signing and encrypting JWT tokens"
to match standard PEM formatting and clear wording.

In `@apps/vercel/.env.example`:
- Around line 23-24: The PEM example in the env example currently has an extra
space before the closing dashes (e.g. "-----BEGIN PUBLIC KEY -----" / "-----END
PUBLIC KEY -----"); update the example string used for the "PEM-encoded RSA
public/private key for signing and encrypting JWT tokens" entry so the markers
are correctly formatted without the extra space ("-----BEGIN PUBLIC KEY-----"
and "-----END PUBLIC KEY-----"), matching the fixed format used in
apps/supabase/.env.example.
- Around line 33-36: Fix the typo in the environment comment by changing
"PEM-encode" to "PEM-encoded" and add a missing blank line before the OAuth
section; specifically update the comment line that precedes
AURA_AUTH_PUBLIC_KEY, AURA_AUTH_PRIVATE_KEY, and AURA_AUTH_ALGORITHM to read
"PEM-encoded RSA public/private key either in 'signed' or 'encrypted' JWT mode
(JWT with JWS or JWE)" and insert a blank line separating this block from the
following OAuth-related env vars/section.

---

Nitpick comments:
In `@docs/src/content/docs/configuration/env.mdx`:
- Around line 146-165: The header "Loading PEM variables from files" doesn't
match the examples which show inline PEM values; update the docs to either (A)
rename the section to "Specifying PEM variables inline" and keep the current
examples for AURA_AUTH_PUBLIC_KEY / AURA_AUTH_PRIVATE_KEY and the
AURA_AUTH_SIGNING_* / AURA_AUTH_ENCRYPTION_* variables, or (B) show the actual
file-loading approach supported by the app (for example using *_FILE or a shell
command to read public.pem/private.pem into env vars) and replace the inline PEM
examples with the file-based usage for the same environment variable names.

In `@packages/core/src/shared/crypto.ts`:
- Around line 146-153: The importPEMKeyPair function currently imports both keys
with extractable: true; change the private key import to non-extractable to
follow least privilege—update the importPKCS8 call inside importPEMKeyPair to
use { extractable: false } for the privateKey while leaving importSPKI for the
publicKey as-is (or true), ensuring existing consumers like createJWT,
createJWS, and createJWE continue to operate without requiring key export
capability.

In `@packages/core/src/shared/errors.ts`:
- Around line 94-104: Add a type guard for the new AuthJoseInitializationError
class and include the class in the isAuthErrorWithCode check: implement a
function isAuthJoseInitializationError(value: unknown): value is
AuthJoseInitializationError that returns true when value is an object with name
"AuthJoseInitializationError" (or instanceof AuthJoseInitializationError) and
has a string code, and then update the existing isAuthErrorWithCode predicate to
also recognize AuthJoseInitializationError alongside the other error classes so
the new class is treated as an error that carries a code.

In `@packages/core/test/env.test.ts`:
- Around line 32-44: The test "direct PEM formatted RSA keys" is marked async
but contains no await; remove the unnecessary async keyword from the test
callback to avoid misleading async usage—locate the test function named
test("direct PEM formatted RSA keys", ...) in env.test.ts and change the
callback from async () => { ... } to () => { ... } (no other changes to the PEM
string, vi.stubEnv call, or expect assertion).

In `@packages/core/test/presets.ts`:
- Around line 60-68: Add a clear, single-line comment immediately above the
RSA256PublicKey constant (the test fixture PEM string) stating that these are
test-only/public-only keys and not secrets (e.g., "Test fixture — non-secret
public key used only in tests") so static analysis and future maintainers
understand this is safe to keep in source; update the comment near the
RSA256PublicKey declaration and, if your tooling supports it, include a short
note like "DO NOT USE IN PRODUCTION" to make intent explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 264b3007-e7fc-4e80-aceb-0a4788e10c17

📥 Commits

Reviewing files that changed from the base of the PR and between 5a4b8e0 and eb82d5d.

📒 Files selected for processing (24)
  • apps/astro/.env.example
  • apps/bun/.env.example
  • apps/cloudflare/.env.example
  • apps/deno/.env.example
  • apps/elysia/.env.example
  • apps/express/.env.example
  • apps/hono/.env.example
  • apps/nextjs/app-router/.env.example
  • apps/nextjs/pages-router/.env.example
  • apps/nuxt/.env.example
  • apps/oak/.env.example
  • apps/react-router/.env.example
  • apps/supabase/.env.example
  • apps/tanstack-start/.env.example
  • apps/vercel/.env.example
  • docs/src/content/docs/configuration/env.mdx
  • packages/core/src/@types/session.ts
  • packages/core/src/jose.ts
  • packages/core/src/shared/assert.ts
  • packages/core/src/shared/crypto.ts
  • packages/core/src/shared/errors.ts
  • packages/core/test/env.test.ts
  • packages/core/test/jose.test.ts
  • packages/core/test/presets.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/core/src/shared/assert.ts
  • packages/core/test/jose.test.ts
  • packages/core/src/jose.ts

Comment thread docs/src/content/docs/configuration/env.mdx
Comment thread docs/src/content/docs/configuration/env.mdx Outdated
Comment thread docs/src/content/docs/configuration/env.mdx
Comment thread packages/core/src/@types/session.ts
@halvaradop halvaradop merged commit 9aeeeed into master Apr 28, 2026
7 checks passed
@halvaradop halvaradop deleted the feat/support-pem-format branch April 28, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

experimental feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant