-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
AWS Load Balancer Auth #514
Comments
Interesting! Could you provide the code that you tried that did not work? Off the top of my head it should be pretty easy, and would be something along the lines of: // this should always work
console.log(jwt.decode(token));
const pubKey = fs.readFileSync('/path/to/publickey'); // replace this line with the HTTP request to get the key
jwt.verify(token, pubKey, (err, decoded) => {
console.log('err:', err);
console.log(decoded);
}); |
This is what I was trying to do but I've even tried your example and it still didn't work. The only thing I added was the const verifyJwt = async (token, db) => {
const encoded_jwt_header = token.split('.')[0];
const decoded_jwt = JSON.parse(base64.decode(encoded_jwt_header));
const request = await fetch(
`https://public-keys.auth.elb.us-west-2.amazonaws.com/${decoded_jwt.kid}`,
);
const cert = await request.text(); // -----BEGIN PUBLIC KEY----...
return new Promise((resolve, reject) => {
jwt.verify(
token,
cert,
{ algorithms: ['ES256'] },
async (err, decoded) => {
if (err) {
reject(err);
}
resolve(decoded);
},
);
});
}; |
Could you provide the output/error that occurs from the code you have above? For reference, the following is an example the works with a ECDSA + P-256 + SHA256 public/private pair, partially taken from the tests: 'use strict';
const jwt = require('jsonwebtoken');
const es256PrivateKey = '-----BEGIN EC PARAMETERS-----\n' +
'MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////\n' +
'/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6\n' +
'k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+\n' +
'kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK\n' +
'fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz\n' +
'ucrC/GMlUQIBAQ==\n' +
'-----END EC PARAMETERS-----\n' +
'-----BEGIN EC PRIVATE KEY-----\n' +
'MIIBaAIBAQQgeg2m9tJJsnURyjTUihohiJahj9ETy3csUIt4EYrV+J2ggfowgfcC\n' +
'AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\n' +
'MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\n' +
'vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\n' +
'axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\n' +
'K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\n' +
'YyVRAgEBoUQDQgAEEWluurrkZECnq27UpNauq16f9+5DDMFJZ3HV43Ujc3tcXQ++\n' +
'N1T/0CAA8ve286f32s7rkqX/pPokI/HBpP5p3g==\n' +
'-----END EC PRIVATE KEY-----\n';
const es256PublicKey = '-----BEGIN PUBLIC KEY-----\n' +
'MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n' +
'AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n' +
'///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n' +
'NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n' +
'RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n' +
'//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABBFpbrq65GRAp6tu1KTWrqte\n' +
'n/fuQwzBSWdx1eN1I3N7XF0PvjdU/9AgAPL3tvOn99rO65Kl/6T6JCPxwaT+ad4=\n' +
'-----END PUBLIC KEY-----\n';
async function main() {
const token = await new Promise((resolve, reject) => {
jwt.sign({foo: 'bar'}, es256PrivateKey, { algorithm: 'ES256'}, (e, t) => {
if (e) {
return reject(e);
}
resolve(t);
});
});
console.log('token:', token);
console.log('decoded:', jwt.decode(token, {complete: true}));
const verified = await new Promise((resolve, reject) => {
jwt.verify(
token,
es256PublicKey,
{ algorithms: ['ES256'] },
async (err, decoded) => {
if (err) {
reject(err);
}
resolve(decoded);
},
);
});
console.log('verified:', verified);
}
main()
.catch((err) => console.log(err))
; |
Same data added to jwt.io |
@MitMaro figured it out and found this: |
That's a common mistake but Amazon should know better. Should be easy to do a simple string replace to work around the problem. |
@delianides @MitMaro Could you guys clarify the solution a bit more? What exactly are you string replacing the non url encoded bits? |
@jreeter , Amazon is using base64 to encode the tokens, which has a different character set than base64url, which is what the JWT specification requires. Specifically, the Untested Code, but the basic idea would be: const correctToken = token.replace(/+/g, '-').replace(/\//g, '_'); |
Just wanted to add that we're having the same issue. Converting token encoding to base64url will allow the library to decode it, however, it will also cause signature verification to fail (both with the library as well as on jwt.io, while using the original token and pubkey will successfully validate on jwt.io). |
@daerion I found a way to make this work, but it's not pretty...... Basically, the verify method in this library won't work, but the signature can be verified using the underlying node-jwa library. Then you just have to check things like is the token still valid (I am only checking if token is not expired):
|
@morganabel Thanks for sharing your implementation :) |
Just ran into the same issue... |
AWS recently added the functionality to authenticate a user on the load balancer and have a authenticated and hydrated user details in the request header.
I wasn't able to decode the object that comes from the load balancer even though it will decode on jwt.io. The example AWS give is in python but should be straight forward enough to decode the token.
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html
Has anyone attempted to decode the
x-amzn-oidc-data
header usingjwt.decode
?The text was updated successfully, but these errors were encountered: