A proxy that can be used transparently to front any cognito client. It can be deployed as lambda@edge.
This proxy is based on AWS Security Blog post Protect public clients for Amazon Cognito by using an Amazon CloudFront proxy.
With this proxy you can go beyond Cognito's Advanced Security and implement security controls on the proxy itself or through Web Application Firewall.
import { createHandler } from 'cognito-proxy';
export const handler = createHandler({
secretLookup: async (clientId) => {
const clientSecret = await secretLookupCustomImplementation(clientId)
return clientSecret;
}
})
The secretLookup
function implements a strategy to lookup your secrets. For your convenience, this package has with the following strategies:
- fetchFromCognito
- fetchFromSSM
- constant
In the following case the strategy will perform the DescribeUserPoolClient action in Cognito to lookup the secret.
The fetchFromCognito
strategy needs to receive an object mapping all supported clientIds to its pool ids.
One advantage of this strategy is that you don't have to update secrets manually. The disadvantage is the need for an additional request to cognito on every request.
For this strategy to work you need to setup the right IAM permissions to your function to read cognito data.
import { createHandler, fetchFromCognito } from 'cognito-proxy';
export const handler = createHandler({
secretLookup: fetchFromCognito({"my-client-id": "my-pool-id"})
})
One common strategy is to store and look secrets up in SSM.
For this strategy to work you need to setup the right IAM permissions to your function to read the relevant SSM params.
import { createHandler, fetchFromCognito } from 'cognito-proxy';
export const handler = createHandler({
secretLookup: fetchFromSSM()
})
The default behavior is to fetch a secret with the second part of the function name (as done in the AWS article). You can simply override that, for instance, to have a secret key based on the client id:
import { createHandler, fetchFromCognito } from 'cognito-proxy';
export const handler = createHandler({
secretLookup: fetchFromSSM({
secretIdLookup: (clientId) => `my-secret.${clientId}`
})
})
import { createHandler, constant } from 'cognito-proxy';
export const handler = createHandler({
secretLookup: constant({'my-client-id': 'my-client-secret'})
})
It can also be a string.
import { createHandler, constant } from 'cognito-proxy';
export const handler = createHandler({
secretLookup: constant('my-client-secret')
})
[] Provide ready-made CloudFormation and CDK recipes for deployment.