-
Notifications
You must be signed in to change notification settings - Fork 37
Add support for direct public key JWT verification without JWKS disco… #176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
arpit-jn
wants to merge
1
commit into
main
Choose a base branch
from
gh-133
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { exportJWK, generateKeyPair } from 'jose'; | ||
import nock from 'nock'; | ||
import { jwtVerifier } from '../src'; | ||
import { createJwt } from './helpers'; | ||
|
||
describe('public-key verification', () => { | ||
beforeEach(() => { | ||
nock.cleanAll(); | ||
}); | ||
|
||
it('should verify a token with a directly provided public key', async () => { | ||
// Generate a key pair for testing | ||
const { publicKey, privateKey } = await generateKeyPair('RS256'); | ||
|
||
// Create a JWT signed with the private key | ||
const tokenPayload = { foo: 'bar' }; | ||
const jwt = await createJwt({ | ||
payload: tokenPayload, | ||
privateKey: privateKey | ||
}); | ||
|
||
// Verify the JWT using the public key directly | ||
const verify = jwtVerifier({ | ||
issuer: 'https://issuer.example.com/', | ||
audience: 'https://api/', | ||
secret: publicKey | ||
}); | ||
|
||
const result = await verify(jwt); | ||
expect(result.payload.foo).toBe('bar'); | ||
}); | ||
|
||
it('should verify a token with directly provided public key when tokenSigningAlg is specified', async () => { | ||
// Generate a key pair for testing | ||
const { publicKey, privateKey } = await generateKeyPair('RS256'); | ||
|
||
// Create a JWT signed with the private key | ||
const tokenPayload = { foo: 'bar' }; | ||
const jwt = await createJwt({ | ||
payload: tokenPayload, | ||
privateKey: privateKey | ||
}); | ||
|
||
// Verify the JWT using the public key directly with explicit alg | ||
const verify = jwtVerifier({ | ||
issuer: 'https://issuer.example.com/', | ||
audience: 'https://api/', | ||
secret: publicKey, | ||
tokenSigningAlg: 'RS256' | ||
}); | ||
|
||
const result = await verify(jwt); | ||
expect(result.payload.foo).toBe('bar'); | ||
}); | ||
|
||
it('should fail to verify when using mismatched keys', async () => { | ||
// Generate two different key pairs | ||
const keyPair1 = await generateKeyPair('RS256'); | ||
const keyPair2 = await generateKeyPair('RS256'); | ||
|
||
// Create JWT with first private key | ||
const jwt = await createJwt({ | ||
payload: { test: 'data' }, | ||
privateKey: keyPair1.privateKey | ||
}); | ||
|
||
// Try to verify with second key's public key (should fail) | ||
const verify = jwtVerifier({ | ||
issuer: 'https://issuer.example.com/', | ||
audience: 'https://api/', | ||
secret: keyPair2.publicKey | ||
}); | ||
|
||
await expect(verify(jwt)).rejects.toThrow(); | ||
}); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
packages/express-oauth2-jwt-bearer/examples/direct-public-key.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Direct Public Key Verification Example | ||
|
||
Below is an example of how to use the library to verify JWTs with a directly provided public key (no JWKS or discovery): | ||
|
||
```js | ||
const { jwtVerifier } = require('access-token-jwt'); | ||
// or: import { jwtVerifier } from 'access-token-jwt'; | ||
|
||
// You could load your public key from a file, environment variable, etc. | ||
// This is just an example of how you'd use it once you have the key | ||
// (could be a CryptoKey, KeyObject, etc.) | ||
const publicKey = getPublicKeyFromSomewhere(); | ||
|
||
// Set up the verifier with the public key | ||
const verify = jwtVerifier({ | ||
issuer: 'https://your-issuer.example.com/', | ||
audience: 'https://your-api/', | ||
secret: publicKey // Pass the public key directly | ||
}); | ||
|
||
// Verify a token | ||
try { | ||
const { payload, header } = await verify(token); | ||
console.log('Token verified!', payload); | ||
} catch (err) { | ||
console.error('Token verification failed:', err.message); | ||
} | ||
``` | ||
|
||
With this approach you can bypass JWKS discovery and validation while still properly verifying tokens signed with asymmetric algorithms. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Copilot Autofix
AI 4 months ago
To fix the problem, the unused
exportJWK
import should be removed from the file. This involves editing the import statement on line 1 to excludeexportJWK
. The rest of the code remains unchanged, as this modification does not affect any functionality.