Fix return type annotation in loadJWTKeys helper#558
Fix return type annotation in loadJWTKeys helper#558
Conversation
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@cypress.config.ts`:
- Around line 17-22: The current fixture-loading block (jwtKeysPath / jwtKeys /
config.env.jwtPublicKey) unconditionally sets Cypress env from a local file;
change it to only set config.env.jwtPublicKey when the app is actually
configured by checking process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY (or set an
explicit flag like config.env.jwtPublicKeyConfigured) and use that to gate
setting config.env.jwtPublicKey; update the same logic in the other similar
block (lines referenced) so tests rely on NEXT_PUBLIC_JWT_PUBLIC_KEY presence
rather than a local fixture.
In `@cypress/fixtures/jwt-keys.json`:
- Around line 2-3: Remove the hard-coded "privateKey" value from the
jwt-keys.json fixture and stop committing private keys; keep only the
"publicKey" (or a placeholder). Update any tests or helpers that import
jwt-keys.json to obtain the private key at runtime instead—either by calling a
new helper like generateTestKeyPair() (which returns { publicKey, privateKey })
in a test setup hook (e.g., beforeAll/beforeEach) or by reading
process.env.TEST_JWT_PRIVATE_KEY injected by your CI/setup script; ensure
jwt-keys.json only contains the publicKey and that the generated/private key is
never written back to the repo. Also add/mention rotate credentials if this key
was already committed.
In `@cypress/support/jwt-helper.ts`:
- Around line 25-27: The function loadJWTKeys currently declares a return type
of JWTKeys but actually returns a Cypress chainable; change its signature to
return Cypress.Chainable<JWTKeys> (i.e., update the return type on loadJWTKeys)
so the TypeScript types reflect that it returns cy.fixture(...).then(...);
update any callers that assumed a synchronous JWTKeys value to use .then(...) or
await within a Cypress command if necessary (search for loadJWTKeys usages to
adjust).
- Around line 8-104: The jwt.sign/verify calls in generateTestJWT,
generateExpiredTestJWT and verifyTestJWT (used by setAuthenticatedSession and
loadJWTKeys) rely on Node's crypto and will break when bundled for the browser;
move JWT signing and verification into Cypress Node tasks instead (implement
cy.task handlers that use jsonwebtoken on the Node side and call those tasks
from generateTestJWT/generateExpiredTestJWT/verifyTestJWT) or, as an
alternative, configure browser polyfills or swap to a browser-compatible library
(e.g., jose) and update these functions to call the new implementation; ensure
setAuthenticatedSession continues to call the refactored generateTestJWT task
and that loadJWTKeys still returns the fixture via cy.fixture.
🧹 Nitpick comments (3)
docs/JWT_FIXTURES_IMPLEMENTATION.md (1)
19-40: Add language identifier to fenced code block.The file structure code block is missing a language specifier, which triggers a linting warning. Consider adding
textorplaintextfor consistency.📝 Suggested fix
-``` +```text cypress/ ├── fixtures/ │ ├── jwt-keys.json # Test RSA key pair (NEW)src/components/Header/NavRight.test.tsx (1)
83-109: Consider using Cypress's skip mechanism for clearer test reporting.The current pattern with
if (!condition) { cy.log(...); return; }silently passes the test rather than marking it as skipped in test reports. This can make it harder to identify which tests were actually executed vs. skipped.💡 Alternative using it.skip or describe block
You could extract the conditional into a wrapper or use Cypress's built-in skip:
// Option 1: Conditional describe block const jwtConfigured = Cypress.env('jwtPublicKey') || Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY') describe('Valid JWT tests', { }, () => { before(function() { if (!jwtConfigured) { this.skip() } }) it('should show signed in content when valid JWT token is present', () => { // test code without the skip logic }) })This approach provides clearer test reporting showing tests as "skipped" rather than "passed".
cypress/e2e/jwtAuth.test.ts (1)
22-51: Optimize conditional test execution.The
beforeEachat lines 23-27 always executessetAuthenticatedSession, even when the tests will be immediately skipped due to missing JWT configuration. Consider moving the skip check to thebeforeEachor restructuring to avoid unnecessary setup.💡 Suggested optimization
describe('Authenticated User (with valid JWT)', () => { + before(function() { + if (!Cypress.env('jwtPublicKey') && !Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')) { + cy.log('Skipping: NEXT_PUBLIC_JWT_PUBLIC_KEY not configured for tests') + this.skip() + } + }) + beforeEach(() => { - // Set up authenticated session with valid JWT token using test fixtures - // This will work if NEXT_PUBLIC_JWT_PUBLIC_KEY is set to the test public key setAuthenticatedSession({ uid: 'test-user-123', name: 'Test User' }) }) it('should display user name when authenticated with valid JWT', () => { - // Skip if JWT public key is not configured for tests - if (!Cypress.env('jwtPublicKey') && !Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')) { - cy.log('Skipping: NEXT_PUBLIC_JWT_PUBLIC_KEY not configured for tests') - return - } - cy.visit('/') cy.get('#sign-in', { timeout: 30000 }).should('be.visible') }) it('should show user dropdown menu when authenticated with valid JWT', () => { - // Skip if JWT public key is not configured for tests - if (!Cypress.env('jwtPublicKey') && !Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY')) { - cy.log('Skipping: NEXT_PUBLIC_JWT_PUBLIC_KEY not configured for tests') - return - } - cy.visit('/')
cypress.config.ts
Outdated
| // Load JWT public key from fixture for tests | ||
| const jwtKeysPath = path.join(__dirname, 'cypress', 'fixtures', 'jwt-keys.json') | ||
| if (fs.existsSync(jwtKeysPath)) { | ||
| const jwtKeys = JSON.parse(fs.readFileSync(jwtKeysPath, 'utf8')) | ||
| config.env.jwtPublicKey = jwtKeys.publicKey | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, examine the cypress.config.ts file to see full context
fd cypress.config.ts -type f | head -5Repository: datacite/akita
Length of output: 228
🏁 Script executed:
# Find and read the full cypress.config.ts file
cat -n cypress.config.ts 2>/dev/null || echo "File not found at root"Repository: datacite/akita
Length of output: 1848
🏁 Script executed:
# Search for JWT-related skip patterns in test files
rg -n 'describe\.skip|it\.skip|xit\(|xdescribe\(|skip\(|jwtPublicKey|JWT_PUBLIC_KEY|NEXT_PUBLIC_JWT_PUBLIC_KEY' --type ts --type js | head -50Repository: datacite/akita
Length of output: 1724
🏁 Script executed:
# Look for how Cypress.env is used with JWT configuration in tests
rg -B3 -A3 "Cypress\.env\('jwtPublicKey'\)|skipIf|skip.*jwt|jwt.*skip" --type ts --type js | head -60Repository: datacite/akita
Length of output: 1719
Gate JWT test enablement on NEXT_PUBLIC_JWT_PUBLIC_KEY instead of local fixture (prevents test mismatch with unconfigurated app).
The fixture (cypress/fixtures/jwt-keys.json) is unconditionally loaded if it exists, which always sets config.env.jwtPublicKey. Tests skip only when both Cypress.env('jwtPublicKey') AND Cypress.env('NEXT_PUBLIC_JWT_PUBLIC_KEY') are absent—so with the fixture present, the skip condition never triggers even when the app isn't configured with JWT. This causes tests to run with a test key while the app may be using a different or missing key, creating false positives.
Instead, check process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY and set the Cypress env only when that variable is present, or expose an explicit jwtPublicKeyConfigured flag to indicate whether JWT is ready for testing.
Suggested adjustment (illustrative)
- const jwtKeysPath = path.join(__dirname, 'cypress', 'fixtures', 'jwt-keys.json')
- if (fs.existsSync(jwtKeysPath)) {
- const jwtKeys = JSON.parse(fs.readFileSync(jwtKeysPath, 'utf8'))
- config.env.jwtPublicKey = jwtKeys.publicKey
- }
+ const envPublicKey = process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY
+ if (envPublicKey) {
+ config.env.jwtPublicKey = envPublicKey
+ config.env.jwtPublicKeyConfigured = true
+ } else {
+ config.env.jwtPublicKeyConfigured = false
+ }Also applies to: 31-36
🤖 Prompt for AI Agents
In `@cypress.config.ts` around lines 17 - 22, The current fixture-loading block
(jwtKeysPath / jwtKeys / config.env.jwtPublicKey) unconditionally sets Cypress
env from a local file; change it to only set config.env.jwtPublicKey when the
app is actually configured by checking process.env.NEXT_PUBLIC_JWT_PUBLIC_KEY
(or set an explicit flag like config.env.jwtPublicKeyConfigured) and use that to
gate setting config.env.jwtPublicKey; update the same logic in the other similar
block (lines referenced) so tests rely on NEXT_PUBLIC_JWT_PUBLIC_KEY presence
rather than a local fixture.
cypress/fixtures/jwt-keys.json
Outdated
| "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj760PNWDk5AWonv/G63Q\n08b1XAqUdCVttXLxr6AEXcJeYWXwDPRZAGKBpMTVcu0SIl7I958ebVx2A1I4dNAZ\n6xCku2bgOzoOiFJqNF1EzaxhHbk2gBQt6q92X5RaPFZh3UUkmvISACoiDH+Mja2W\nkW3o8o4iRWaRUvo0sRpbv+O7PSx+3FBABGZSSz1wV7rz7YMjDUjHCF2gsS3XKeA3\nZzmwYlLmpxM1kD6h/XloO9OHgH2h2IlOyhm7VkhRYYc1auj5zJYKzKkWfCvbozF+\nrufZNFqMGjlUzmH5KYr4CcnuzYFTN0RxUJrCs1UDh/KbI2wZx3ZXXt4zp4QQNAO0\nRQIDAQAB\n-----END PUBLIC KEY-----", | ||
| "privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCPvrQ81YOTkBai\ne/8brdDTxvVcCpR0JW21cvGvoARdwl5hZfAM9FkAYoGkxNVy7RIiXsj3nx5tXHYD\nUjh00BnrEKS7ZuA7Og6IUmo0XUTNrGEduTaAFC3qr3ZflFo8VmHdRSSa8hIAKiIM\nf4yNrZaRbejyjiJFZpFS+jSxGlu/47s9LH7cUEAEZlJLPXBXuvPtgyMNSMcIXaCx\nLdcp4DdnObBiUuanEzWQPqH9eWg704eAfaHYiU7KGbtWSFFhhzVq6PnMlgrMqRZ8\nK9ujMX6u59k0WowaOVTOYfkpivgJye7NgVM3RHFQmsKzVQOH8psjbBnHdlde3jOn\nhBA0A7RFAgMBAAECggEAOcByVKCqCO7SkTyFPb8jT/q3GGAtzc492jFQtfFx36OY\nXMRiYioH2hY5pRPp+A8UgpeXYZld1a1YwrPVd+UmDKG2tY47F8CXFyEZh2lTm9ie\neh0wLtwsqIYPZo5JhMVl80r0zoXkQomq/V9/fmqYPFyuw0jkrwJq764T3nXLF/hS\nL8r9ieDtvxHjeDA+0Cj51wYZijQdeKrs/LLvUjW+du8quZfbdIR2pXDJMVORkTl9\n4ujt+CnpapUlCwzRqlr5Ln6AT+50n4Bx0J01k3da7svXQnLW7pvlkrenJtRG7/xJ\nZGc+TFvQQ6Gb/GeadVfLQNMPkHwEXm1lGFRa3Q5nvwKBgQDJMVteXwT7VFvvvq8X\nQGzHIIF5Go9I2l/DW5QFU/FKUsAOR5RqlCq4+WQry5C/KpULtTatarco0kp00oAO\ncxt+J3ph55n1xxepKjJrk1csCwHw6sKZcI0sCgy2uimZuyNBHV/k+aNWYN4cVj0t\nEw18TBn/cntVZJJQRApnLAw2nwKBgQC25xaTq0g1l+houN1TC2W0H9QpYPyXaqvS\n9swAo4Gvv5ESoYM64qGs9v7gU0xmf7xP2peNGf0+KGXIzhLgC9mAsiGgZISRI/NP\njJTtyty3Lgdct5z2BvyJ7aMdPdg1pldyE73nVFXU+TK9Lq+61diRVTcUf3td0BBc\nksQq0sgemwKBgBUX5qNrRONwwb7N+B9w8rah0tE2lqUlt/qMZGV2moqXSGl22bme\n1SfVhcoNqpxQQ5YZpqTh1lgiTAoZc7GQIebFDtCq7npVKEblFKowpWgJs2dlxYc+\nxJ5EY3bY57mlZBnUkZQ5FAXfXAoOhJVwNO6+L8+XWhTm2Wwu5gRRGuqzAoGAAXCo\nWNlMZD+h8NEjzPeWAWkOvpSo6HhKigqvaIHhD4UumzryUZBfPYFkWFfPji8LSIWs\nE8xUlhyzUHVu6JyvRbghU6X29T2XONUehxDF1Btkq3I2pik/68YXNq+5+BIrNha5\ntAyR8G9V2u93Kr1sSxikqmCmlAKDXnc5XCz0rmkCgYBfiFh8BKVjjOgThDu3SRXx\nx5p8BZidnH0gv+7ugdIycQ+oLuDFK2aksrUnQRgTyoO7t7Op3eg9oXpaOJ48ngCk\nadVZ/LaSNQMjCZNloDMqzgyAs/WKrKRKPUF4BmehfSkIa02leiowv920RV5lz2cn\nAqNjUvBofbfSx4IW+bC3tw==\n-----END PRIVATE KEY-----" |
There was a problem hiding this comment.
Avoid committing a private key to the repo (even test-only).
Secret scanners are already flagging this, and private keys in VCS are a compliance/security risk regardless of intent. Prefer generating the key pair at test runtime (or via a setup script) and keep the private key out of version control; only the public key needs to be committed.
🧰 Tools
🪛 Gitleaks (8.30.0)
[high] 3-3: Identified a Private Key, which may compromise cryptographic security and sensitive data encryption.
(private-key)
🤖 Prompt for AI Agents
In `@cypress/fixtures/jwt-keys.json` around lines 2 - 3, Remove the hard-coded
"privateKey" value from the jwt-keys.json fixture and stop committing private
keys; keep only the "publicKey" (or a placeholder). Update any tests or helpers
that import jwt-keys.json to obtain the private key at runtime instead—either by
calling a new helper like generateTestKeyPair() (which returns { publicKey,
privateKey }) in a test setup hook (e.g., beforeAll/beforeEach) or by reading
process.env.TEST_JWT_PRIVATE_KEY injected by your CI/setup script; ensure
jwt-keys.json only contains the publicKey and that the generated/private key is
never written back to the repo. Also add/mention rotate credentials if this key
was already committed.
cypress/support/jwt-helper.ts
Outdated
| import jwt from 'jsonwebtoken' | ||
|
|
||
| export interface JWTPayload { | ||
| uid: string | ||
| name: string | ||
| exp?: number | ||
| iat?: number | ||
| } | ||
|
|
||
| export interface JWTKeys { | ||
| publicKey: string | ||
| privateKey: string | ||
| } | ||
|
|
||
| /** | ||
| * Load JWT test keys from fixtures | ||
| */ | ||
| export function loadJWTKeys(): JWTKeys { | ||
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys) | ||
| } | ||
|
|
||
| /** | ||
| * Generate a valid JWT token for testing | ||
| * @param payload - The JWT payload (uid and name are required) | ||
| * @param expiresIn - Expiration time (default: '1h') | ||
| * @returns Promise<string> - The signed JWT token | ||
| */ | ||
| export function generateTestJWT( | ||
| payload: JWTPayload, | ||
| expiresIn: string = '1h' | ||
| ): Cypress.Chainable<string> { | ||
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => { | ||
| const token = jwt.sign( | ||
| payload, | ||
| keys.privateKey, | ||
| { | ||
| algorithm: 'RS256', | ||
| expiresIn | ||
| } | ||
| ) | ||
| return token | ||
| }) | ||
| } | ||
|
|
||
| /** | ||
| * Generate an expired JWT token for testing | ||
| * @param payload - The JWT payload | ||
| * @returns Promise<string> - The expired JWT token | ||
| */ | ||
| export function generateExpiredTestJWT( | ||
| payload: JWTPayload | ||
| ): Cypress.Chainable<string> { | ||
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => { | ||
| const token = jwt.sign( | ||
| { ...payload, exp: Math.floor(Date.now() / 1000) - 3600 }, | ||
| keys.privateKey, | ||
| { algorithm: 'RS256' } | ||
| ) | ||
| return token | ||
| }) | ||
| } | ||
|
|
||
| /** | ||
| * Set up authenticated session with a valid JWT token | ||
| * @param user - User information (uid and name) | ||
| * @param expiresIn - Token expiration time (default: '1h') | ||
| */ | ||
| export function setAuthenticatedSession( | ||
| user: { uid: string; name: string }, | ||
| expiresIn: string = '1h' | ||
| ): Cypress.Chainable<void> { | ||
| return generateTestJWT(user, expiresIn).then((token) => { | ||
| const cookieValue = JSON.stringify({ | ||
| authenticated: { | ||
| access_token: token | ||
| } | ||
| }) | ||
| cy.setCookie('_datacite', cookieValue) | ||
| }) | ||
| } | ||
|
|
||
| /** | ||
| * Verify JWT token with public key (for testing verification logic) | ||
| * @param token - The JWT token to verify | ||
| * @returns Promise<any> - The decoded payload or null if verification fails | ||
| */ | ||
| export function verifyTestJWT(token: string): Cypress.Chainable<any> { | ||
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => { | ||
| return new Promise((resolve) => { | ||
| jwt.verify(token, keys.publicKey, { algorithms: ['RS256'] }, (error, payload) => { | ||
| if (error) { | ||
| resolve(null) | ||
| } else { | ||
| resolve(payload) | ||
| } | ||
| }) | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find the Cypress configuration file
fd -e ts -e js "cypress.config" .Repository: datacite/akita
Length of output: 77
🏁 Script executed:
# Check for webpack or bundler configuration
fd -e js -e ts "webpack.config|vite.config|rollup.config" .Repository: datacite/akita
Length of output: 40
🏁 Script executed:
# Search for cy.task implementations and crypto-related configuration
rg -n "cy\.task|crypto|polyfill" cypress/ src/ --type ts --type jsRepository: datacite/akita
Length of output: 126
🏁 Script executed:
# Check what dependencies are installed
find . -name "package.json" -type f | head -5 | xargs catRepository: datacite/akita
Length of output: 7818
🏁 Script executed:
cat -n cypress.config.tsRepository: datacite/akita
Length of output: 1848
🏁 Script executed:
# Search for cy.task implementations related to JWT
rg -n "cy\.task|task.*jwt|jwt.*task" --type ts --type jsRepository: datacite/akita
Length of output: 40
🏁 Script executed:
# Check if there are other Cypress support files that might configure crypto
fd -e ts -e js . cypress/support/ cypress/plugins/Repository: datacite/akita
Length of output: 218
🏁 Script executed:
# Check if there are any tests using the jwt-helper functions
rg -n "generateTestJWT|generateExpiredTestJWT|setAuthenticatedSession|verifyTestJWT" --type ts --type jsRepository: datacite/akita
Length of output: 910
🏁 Script executed:
# Look at the e2e.ts file to see how jwt-helper is used
cat -n cypress/support/e2e.tsRepository: datacite/akita
Length of output: 1224
🏁 Script executed:
# Check if there's webpack configuration for browserify polyfills
cat -n cypress.config.ts | grep -A 20 "webpack"Repository: datacite/akita
Length of output: 196
🏁 Script executed:
# Check if there's any browserify configuration in cypress.config or package.json
rg -n "browserify|polyfill" cypress.config.ts package.jsonRepository: datacite/akita
Length of output: 123
🏁 Script executed:
# Check the actual test files to see if they fail or if there's a workaround
head -100 cypress/e2e/jwtAuth.test.tsRepository: datacite/akita
Length of output: 3523
🏁 Script executed:
# Search for any Node.js crypto mock or polyfill setup
rg -n "crypto|mock|stub" cypress/support/ --type tsRepository: datacite/akita
Length of output: 40
🏁 Script executed:
# Let me check if jsonwebtoken actually works with browserify or if there are any issues reported
# First, check if there's a .browserifyrc or any browserify config
find . -name ".browserifyrc*" -o -name "browserify.config*"Repository: datacite/akita
Length of output: 40
🏁 Script executed:
# Check the component test that uses generateTestJWT to see if it actually passes or is skipped
head -150 src/components/Header/NavRight.test.tsxRepository: datacite/akita
Length of output: 3782
🏁 Script executed:
# Search for any error logs or skipped tests related to JWT
rg -n "skip|pending|xdescribe|xit|TODO.*jwt|FIXME.*jwt" cypress/ src/components/Repository: datacite/akita
Length of output: 390
🏁 Script executed:
# Check if there's a JWT_TEST_SETUP.md to understand the intended design
cat -n cypress/fixtures/JWT_TEST_SETUP.mdRepository: datacite/akita
Length of output: 7679
🏁 Script executed:
# Verify that jsonwebtoken actually has browser compatibility or if there are known issues
# Check if there are any comments in jwt-helper about this
cat -n cypress/support/jwt-helper.ts | head -20Repository: datacite/akita
Length of output: 570
🏁 Script executed:
# Check if jsonwebtoken has browser polyfills or browserify compatibility
# Look for any browserify field in jsonwebtoken's package or any polyfill references
rg -n "browser|polyfill" package.json | grep -A5 -B5 "jsonwebtoken"Repository: datacite/akita
Length of output: 40
🏁 Script executed:
# Check if there's actual test execution in CI that would catch this issue
cat -n .github/workflows/*.yml | grep -A10 -B10 "cypress\|test" | head -100Repository: datacite/akita
Length of output: 3352
🏁 Script executed:
# Try to find if there's any working implementation of cy.task for Node operations
rg -n "cy.task" --type ts --type jsRepository: datacite/akita
Length of output: 40
🏁 Script executed:
# Check if there's any evidence that tests are actually running or being skipped
# Look for test output or CI configuration
find . -name "*.md" -type f | xargs grep -l "test\|jwt" | head -10Repository: datacite/akita
Length of output: 609
🏁 Script executed:
# Search for any web-based implementations or mocks of jwt signing
rg -n "jest.mock|sinon|stub.*jwt" cypress/ src/ --type ts --type jsRepository: datacite/akita
Length of output: 40
🌐 Web query:
jsonwebtoken browserify browser compatibility crypto polyfill
💡 Result:
jsonwebtoken (auth0/node-jsonwebtoken) is fundamentally a Node.js JWT implementation and (transitively) depends on Node core modules like crypto (and often stream, util, etc.), which is why bundling it for the browser with Browserify/Webpack commonly fails unless you add polyfills. [1], [2]
If you still want to bundle jsonwebtoken in the browser
You’ll need Node-core polyfills, most importantly:
crypto→crypto-browserify(a JS port of Node’scryptosubset) [3]- Often also
stream→stream-browserify(becausejsonwebtokenusesjws/streams), plusbuffer,process,utildepending on your bundler/errors. [2]
Typical Webpack 5-style fix (conceptually):
- add
resolve.fallback.crypto = require.resolve("crypto-browserify")(and other fallbacks as required by your build errors) [2] - install the corresponding polyfill packages (e.g.,
crypto-browserify) [3]
Caveat: even if it bundles, this increases bundle size and complexity, and you’re relying on JS crypto polyfills rather than the browser’s native WebCrypto in many cases. [3]
Usually better: use a browser-native JWT/JOSE library
If you need sign/verify in the browser, prefer a library designed for browsers (WebCrypto-first), e.g. jose which explicitly supports browsers and other web runtimes. [4]
If you only need to decode (not validate signatures) in the browser, use a decode-only library like jwt-decode. [5]
Rule of thumb: don’t sign HS256/secret-based JWTs in the browser (the secret would be exposed). Do signing server-side; in the browser, typically only decode/display claims, or verify tokens using public keys when appropriate.
Sources: auth0/node-jsonwebtoken repo [1], Webpack “can’t resolve crypto” error pattern [2], crypto-browserify docs [3], panva/jose support statement [4], auth0/jwt-decode guidance [5].
Move JWT signing/verification to cy.task or add crypto polyfills for browser bundling.
jsonwebtoken is a Node.js library that depends on the crypto module. When bundled for the browser via @cypress/browserify-preprocessor, it will fail at runtime unless you add explicit polyfills (crypto-browserify, stream-browserify, etc.). Tests currently skip when NEXT_PUBLIC_JWT_PUBLIC_KEY is not configured, but they will fail once that variable is set in CI.
Either move jwt.sign() and jwt.verify() into a cy.task that runs in the Node.js process, or install and configure the required polyfills in the bundler (e.g., via a custom webpack override in cypress.config.ts). Alternatively, use a browser-compatible JOSE library like jose if client-side JWT operations are needed.
🤖 Prompt for AI Agents
In `@cypress/support/jwt-helper.ts` around lines 8 - 104, The jwt.sign/verify
calls in generateTestJWT, generateExpiredTestJWT and verifyTestJWT (used by
setAuthenticatedSession and loadJWTKeys) rely on Node's crypto and will break
when bundled for the browser; move JWT signing and verification into Cypress
Node tasks instead (implement cy.task handlers that use jsonwebtoken on the Node
side and call those tasks from
generateTestJWT/generateExpiredTestJWT/verifyTestJWT) or, as an alternative,
configure browser polyfills or swap to a browser-compatible library (e.g., jose)
and update these functions to call the new implementation; ensure
setAuthenticatedSession continues to call the refactored generateTestJWT task
and that loadJWTKeys still returns the fixture via cy.fixture.
cypress/support/jwt-helper.ts
Outdated
| export function loadJWTKeys(): JWTKeys { | ||
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys) | ||
| } |
There was a problem hiding this comment.
Fix loadJWTKeys return type (it returns a Cypress chainable).
The current signature says JWTKeys but returns cy.fixture(...).then(...), which is Cypress.Chainable<JWTKeys>. This is a TypeScript correctness issue and will mislead callers.
Suggested fix
-export function loadJWTKeys(): JWTKeys {
+export function loadJWTKeys(): Cypress.Chainable<JWTKeys> {
return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function loadJWTKeys(): JWTKeys { | |
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys) | |
| } | |
| export function loadJWTKeys(): Cypress.Chainable<JWTKeys> { | |
| return cy.fixture('jwt-keys').then((keys: JWTKeys) => keys) | |
| } |
🤖 Prompt for AI Agents
In `@cypress/support/jwt-helper.ts` around lines 25 - 27, The function loadJWTKeys
currently declares a return type of JWTKeys but actually returns a Cypress
chainable; change its signature to return Cypress.Chainable<JWTKeys> (i.e.,
update the return type on loadJWTKeys) so the TypeScript types reflect that it
returns cy.fixture(...).then(...); update any callers that assumed a synchronous
JWTKeys value to use .then(...) or await within a Cypress command if necessary
(search for loadJWTKeys usages to adjust).
Co-authored-by: jrhoads <1517672+jrhoads@users.noreply.github.com>
… for signing and verifying tokens. Update documentation to reflect changes in key management and usage. Ensure private keys are never committed and clarify the role of public keys in tests. Adjust tests to skip gracefully when JWT configuration is incomplete.
akita
|
||||||||||||||||||||||||||||
| Project |
akita
|
| Branch Review |
copilot/add-jwt-tests
|
| Run status |
|
| Run duration | 02m 32s |
| Commit |
|
| Committer | Copilot |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
3
|
|
|
0
|
|
|
3
|
|
|
0
|
|
|
55
|
| View all changes introduced in this branch ↗︎ | |
Tests for review
cypress/e2e/jwtAuth.test.ts • 3 failed tests • Tests
…ety. Ensure it returns an empty string for invalid JSON or parsing errors.
TypeScript compilation failed on
cypress/support/jwt-helper.tsdue to return type mismatch. TheloadJWTKeys()function declared return type asJWTKeysbut returnedCypress.Chainable<JWTKeys>fromcy.fixture().Changes
cypress/support/jwt-helper.ts
This aligns the return type with the other helper functions in the file, all of which correctly declare
Cypress.Chainable<T>return types.💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.
Summary by CodeRabbit
Tests
Chores
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.