aws-samples / aws-samples/cloudfront-authorization-at-edge
[Feature request] Support multiple Cognito user pool clients
- Dominant language
- TypeScript
- Stars
- 534
- Forks
- 165
- PR merge metrics
- No merged PRs in 30d
Description
We have been using this lambda@edge + cognito solution for some time to host an internal static site. We'd like to expand its use so that we can easily spin up other static sites behind cognito auth. Looking at the current implementation, it seems the only way to achieve this is to spin up multiple lambdas@edge (i.e., one parseAuth lambda for each static site). This is because the lambdas search their disk configuration.json for the cognito app id when authenticating. What we'd like is the ability to use a single parseAuth (and others) lambad@edge to handle authorization to multiple different cognito app ids.
One way to achieve this is to convert the app id key in the configuration.json to an app id map, which would map domain names to congito app id. Lambda logic could be updated to look something like this:
parseAuth -- before
~~~
export const handler: CloudFrontRequestHandler = async (event) => {
CONFIG.logger.debug("Event:", event);
const request = event.Records[0].cf.request;
const domainName = request.headers["host"][0].value;
const cognitoTokenEndpoint = `https://${CONFIG.cognitoAuthDomain}/oauth2/token`;
let redirectedFromUri = `https://${domainName}`;
let idTokenInCookies: string | undefined = undefined;
try {
const cookies = common.extractAndParseCookies(
request.headers,
CONFIG.clientId,
CONFIG.cookieCompatibility
);
...
~~~
parseAuth -- after
~~~
export const handler: CloudFrontRequestHandler = async (event) => {
CONFIG.logger.debug("Event:", event);
const request = event.Records[0].cf.request;
const domainName = request.headers["host"][0].value;
const cognitoTokenEndpoint = `https://${CONFIG.cognitoAuthDomain}/oauth2/token`;
let redirectedFromUri = `https://${domainName}`;
let idTokenInCookies: string | undefined = undefined;
try {
const cookies = common.extractAndParseCookies(
request.headers,
CONFIG.clientIdMap[domainName], // <----------- CHANGE HERE
CONFIG.cookieCompatibility
);
...
~~~
Some other tweaks to [getConfigWithJwtVerifier()](https://github.com/aws-samples/cloudfront-authorization-at-edge/blob/0bd6b87cb511df37b8c180accba460dd15f372cb/src/lambda-edge/shared/shared.ts#L230) would also be necessary.
If one wanted to generalize, one could really have the whole confiurationg.json be the value of a map from domainName to config.
Another thought is to be able to override cognito app ID (and potentially other cognito params) with cookies that cloudfront would presumably set. Not sure if I like this as much, given that an unauthorized user could maliciously set cognito parameters via the cookies and you're relying on a developer to make sure they properly rewrite any maliciously formed cookies in their cloudfront distribution.
Anyway, I'd be willing to do fork the repo and implement a version of this. I'd love to contribute back to this project though and am trying to get a sense if such a change would be accepted. I don't necessarily want to maintain a second copy of this whole project just for a small enhancement like this. 😅 Let me know what y'all think!
Thanks,
Jack
Contributor guide
Research direction
Start with the Lambda@Edge parseAuth handler and configuration.json, then inspect getConfigWithJwtVerifier() in src/lambda-edge/shared/shared.ts. Trace how the current clientId and Cognito settings are loaded and used for cookie parsing and JWT verification. Done means one Lambda@Edge configuration can authorize multiple domains with their mapped Cognito app IDs, with the related authentication flows still working.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- authentication, cloud
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100