-
Notifications
You must be signed in to change notification settings - Fork 44
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
[FEATURE REQUEST] Improved support for verifying JWTs from AWS ALB #109
Comments
Chatted about this issue with another user (Nicolas V) and to support ALB we need the following changes:
ALB public key example, as hosted on
|
We are working on (2) supporting Elliptic Curve and (3) dealing with the weird padding seems simple enough, but (1) is to be designed and implemented: how to "nicely" deal with the non-standard JWKS. Current thinking is to create a new file and subpath, import { JwtRsaVerifier } from "aws-jwt-verify";
import { AwsAlbJwksCache } from "aws-jwt-verify/jwks-adapters";
const verifier = JwtRsaVerifier.create(
{
issuer: "<issuer",
audience: "<audience>",
},
{
jwksCache: new AwsAlbJwksCache(),
}
); Or for Firebase: import { JwtRsaVerifier } from "aws-jwt-verify";
import { GoogleFirebaseJwksCache } from "aws-jwt-verify/jwks-adapters";
const verifier = JwtRsaVerifier.create(
{
issuer: "<issuer",
audience: "<audience>",
},
{
jwksCache: new GoogleJwksCache(),
}
); An implementation of such a JWKS cache is pretty simple, here's one for Firebase (adapted from #152 using Firebase as example because we already typed this one out earlier): import { JsonFetcher, SimpleJsonFetcher } from "aws-jwt-verify/https";
import { SimpleJwksCache } from "aws-jwt-verify/jwk";
import crypto from "crypto";
type GoogleFirebaseJwks = Record<string, string>;
class GoogleFirebaseJwksFetcher implements JsonFetcher {
private fetcher = new SimpleJsonFetcher();
public async fetch(...params: Parameters<JsonFetcher["fetch"]>) {
return this.fetcher.fetch(...params).then((response) => {
const keys = Object.entries(response as GoogleFirebaseJwks).map(
([kid, x509cert]) => {
return {
kid,
kty: "RSA",
use: "sig",
...new crypto.X509Certificate(x509cert).publicKey.export({
format: "jwk",
}),
};
}
);
return { keys };
});
}
}
export class GoogleFirebaseJwksCache extends SimpleJwksCache {
constructor() {
super({ fetcher: new GoogleFirebaseJwksFetcher() });
}
} Of course having done that we could also expose the complete assembled JWT verifiers at module level (well, at least the AWS ones ;) ): import { AwsAlbJwtVerifier } from "aws-jwt-verify";
const verifier = AwsAlbJwtVerifier.create(
{
issuer: "<issuer",
audience: "<audience>",
}, |
Above the current thoughts we have on this, brought in the interest of full disclosure, and to collect feedback! If you have an opinion please share |
Already at this point (and even if this does not get implemented, after all) I want to say: thank you for working on this! Unfortunately my knowledge regarding the details is not deep enough for contributing. :( |
I would like to thank you again Otto for working on this feature. I like your proposal about implementing a specific cache and fetcher for the feature According to the proposal, I would like to add what I have in mind about how this feature would be integrated into an real API protected by the ALB cognito feature. //Verification of the access token (signed by cognito) in the header x-amzn-oidc-accesstoken"
const accessTokenVerifier = CognitoJwtVerifier.create({
userPoolId: 'xxx',
clientId: 'xxx',
tokenUser:'access'
});
const accessTokenPayload = accessTokenVerifier.verify(request.headers["x-amzn-oidc-accesstoken"]);
//Verification of the data token (signed by the ALB) in the header x-amzn-oidc-data"
const dataTokenVerifier = AlbJwtVerifier.create({
region: 'eu-west-1',
});
const dataTokenPayload = dataTokenVerifier.verify(request.headers["x-amzn-oidc-data"]); The code above assume that the developper want to parse the access and data token. Of course we could imagine that only one of them could be verified if the other is not need. I have started looking about how to implement the ALB cache and the ALB fetcher. It seems a little bit more complexe than the Google Firebase example. The current SimpleJwksCache algorithm is roughly the one below:
However, whean dealing with the ALB, the jwks uri is templated (the kid is inside the uri path). It means that the hydratation ( It's why the Alb cache can't reuse the SimpleJwksCache and need to reimplemente is own logic ( |
Thanks @NicolasViaud for all the details! I have not yet looked closely at how ALB actually "does it" and was expecting it to be easier. I want to have a chat with the ALB team about this. Maybe they have some insights to share that could be helpful. I'll report back here once I've done that. I wonder how many unique kids there can potentially be, and if the associated public keys are indeed immutable as you would expect, but that I will ask the ALB team. |
A thing we could start building, if you want to get hands dirty already, is adding an ALB with OIDC auth to the CDK stack for the end to end test: https://github.com/awslabs/aws-jwt-verify/blob/main/tests/cognito/lib/cognito-stack.ts |
Update: had a chat with ALB team. The following is my summary (note: do not treat this as product documentation for ALB, officially this might change at any time):
So, looks like a simple LRU cache with size 2 will thus work, for caching ALB JWKs. This is the current interface for Lines 69 to 74 in 8bb9b6e
Agree with your reasoning above @NicolasViaud and I think we should create a new Jwks cache, we can't reuse the SimpleJwksCache here. The new JWKS cache for AWS ALB, should support |
Commenting to signal interest: it would be really great if this library supported JWT verification from ALB The Right Way. We've got all sorts of implementations in various non-JS/TS languages lying around, but having one provided by AWS would set at least my mind at ease. |
Thanks @ahinkka and yes totally agree |
I am very interested in this. I currently have a Node implementation for verifying Firebase JWT's in lambda@edge with the jsonwebtoken lib. Currently handling fetching and caching of the Google public certs with some custom code. I need to add support for Cognito tokens, so it would be great to consolidate on one library to do it all. |
I'm bumping my head into this right now, after authoring a webapp with Cognito auth on the ALB.. I simply want to define a What are we as users supposed to do in the meantime? Is it safe to just accept the unverified claims from the |
Here are the ALB docs that specify how to verify their JWT: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html#user-claims-encoding There is a Python code sample in there that shows how to do it. |
I'm very happy to find this thread, along with #166. +1 to the thanks others have already offered. my experience to this pointI've been trying to use the jsonwebtoken library's I can get the (If seeing some example code would be helpful, let me know, and I can share.) confirming your plansMy initial understanding is that the planned
Do you have any sense of timeline yet? No worries if it's too early to say, but it would be helpful to know whether help is imminent, or if we need to pivot to a non-ALB-based solution. AWS references to current state of playJust within the last week, the Networking & Content Delivery blog posted Security best practices when using ALB authentication. Similar to the docs @ottokruse linked, they offer a Python example. Apparently the Python library can handle the non-standard padding? 🤷 The blog states ...
They don't offer a mention of how many of those "multiple libraries" will actually support ALB JWTs. I've not yet found any for JavaScript. I'll eventually be searching for a .NET solution as well. If anyone here is aware of libraries that do already work, please share! The docs seem a little more forthright about the current state of play ...
|
Yes we aim to make ALB JWT verification work in the lib here, aws-jwt-verify, so you wouldn't need any other lib for it then. (It would eg also include fetching the public key, caching it, and checking standard claims such as exp, iss, and the specifics for AWS ALB). Timeline without guarantees: this year. It's stalling a bit now due to holiday season, but we're not far off and already did some pre work (support ES256). Thanks for linking the blog. |
Another reason why we should add support for AWS ALB: https://www.miggo.io/resources/uncovering-auth-vulnerability-in-aws-alb-albeast TL;DR --> AWS ALB has quirks when signing JWTs, makes sure you check iss field (pretty standard although AWS ALB puts this claim in the JWT header instead of in the payload which is non-standard) but ALSO make sure the |
FWIW, I'm seeing an |
Interesting, their docs say it's in the header, along with |
looks like we know how to deal with the padding issue |
This is happening! |
For convenience, here is a (now expired) JWT from ALB for a test user. This was passed by AWS ALB in the HTTP header
Which decodes to:
|
Support for AWS ALB was released in https://github.com/awslabs/aws-jwt-verify/releases/tag/v5.0.0 However we are working in #176 on making it easier:
Without #176 users will have to take of that themselves, as shown here: aws-jwt-verify/tests/cognito/test/cognito.test.ts Lines 41 to 48 in 9756605
aws-jwt-verify/tests/cognito/test/cognito.test.ts Lines 172 to 197 in 9756605
|
See #71
Let's look into the padding issue and figure out if we can support verifying ALB JWTs?
(Or conclude we don't want that feature in this lib, as long as we have look into it and make up our minds about what is right)
The text was updated successfully, but these errors were encountered: