Add support for cognito user pool authorizer - https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
Upvote this issue if you'd like this feature in the CDK.
This is a :rocket: Feature Request
May be worth checking out and subscribing to https://github.com/aws/aws-cdk-rfcs/issues/95 as well.
Any progress on this feature? Any workaround in the meantime?
Thanks!
@meleksomai - you can use the the construct at the CFN layer - CfnAuthorizer
- to work around this. However, you will need to configure all of the properties correctly yourself.
@nija-at , thanks. I have tried without much success.
I am following the current approach which was suggested in the following comment: https://github.com/aws/aws-cdk/issues/723#issuecomment-504753280 and it works.
I am sharing a sample of the python code which might be helpful to others.
from aws_cdk import (
core,
aws_lambda,
aws_apigateway,
aws_cognito
)
class CustomStack(core.NestedStack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
#--------------------------------
# API Gateway
#--------------------------------
custom_api = aws_apigateway.RestApi(self, "CustomRestApi",
rest_api_name='CustomApiGateway'
)
# Defines the AWS Lambda resources
custom_lambda = aws_lambda.Function(
self, 'CustomHandler',
runtime=aws_lambda.Runtime.PYTHON_3_8,
code=aws_lambda.Code.asset('lambda/'),
handler='post-handler.handler',
)
# Adding the resource
custom_api_resource = custom_api.root.add_resource('management')
# Adding the lambda to the resources
custom_api_method_post = custom_api_resource.add_method('POST',
aws_apigateway.LambdaIntegration(custom_lambda, proxy=True)
)
# API Gateway Cognito Authorizer
cognito_authorizer = aws_apigateway.CfnAuthorizer(
scope=self,
id='CustomCognitoAuthorizer',
rest_api_id=custom_api.rest_api_id,
name='CustomCognitoAuth',
type='COGNITO_USER_POOLS',
identity_source='method.request.header.Authorization',
identity_validation_expression="Bearer (.*)",
provider_arns=[
'arn:aws:cognito-idp:us-XXXX-X:XXXXXXXXXX:userpool/'
'us-XXXX-X_XXXXXXXX']
)
post_method_resource = custom_api_method_post.node.find_child('Resource')
post_method_resource.add_property_override('AuthorizationType', 'COGNITO_USER_POOLS')
post_method_resource.add_property_override( 'AuthorizerId', {"Ref": cognito_authorizer.logical_id})
The configuration is deployed but the authorization is not triggered. I am not sure if this is because I have to provide an Oauth scope when using Cognito Authorizer.
Just ran into this need myself, and since native support doesn't seem to exist yet, here was my attempted workaround for JavaScript/TypeScript using CfnAuthorizer
as suggested above:
References:
COGNITO_USER_POOLS
authorizer, if the OAuth Scopes option isn't specified, API Gateway treats the supplied token as an identity token and verifies the claimed identity against the one from the user pool. Otherwise, API Gateway treats the supplied token as an access token and verifies the access scopes that are claimed in the token against the authorization scopes declared on the method.import { AuthorizationType, CfnAuthorizer } from '@aws-cdk/aws-apigateway'
import { UserPool } from '@aws-cdk/aws-cognito'
const userPool = UserPool.fromUserPoolId(this, 'UserPool', userPoolId)
// ..snip..
const cognitoAuthorizer = new CfnAuthorizer(this, 'CognitoAuthorizer', {
name: 'CognitoAuthorizer',
type: AuthorizationType.COGNITO,
providerArns: [userPool.userPoolArn],
identitySource: 'method.request.header.Authorization',
restApiId: api.restApiId,
})
// ..snip..
Unfortunately, when trying to use this in the authorizer
field of the MethodOptions
(later in my code, not shown above), I get the following error:
TS2741: Property 'authorizerId' is missing in type 'CfnAuthorizer' but required in type 'IAuthorizer'.
Hacking a naive custom 'wrapper' around CfnAuthorizer
to resolve the above, I came up with:
import { Construct } from '@aws-cdk/core'
import { CfnAuthorizer, IAuthorizer } from '@aws-cdk/aws-apigateway'
import { CfnAuthorizerProps } from '@aws-cdk/aws-apigateway/lib/apigateway.generated'
/**
* Custom construct that implements a Cognito based API Gateway Authorizer.
*
* @see https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_author
*
* @see https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.CfnAuthorizer.html
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-authorizer.html
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-enable-cognito-user-pool.html
*
* @see https://github.com/aws/aws-cdk/issues/5618#issuecomment-666922559
*/
export class CognitoApiGatewayAuthorizer extends CfnAuthorizer implements IAuthorizer {
public readonly authorizerId: string
constructor(scope: Construct, id: string, props: CfnAuthorizerProps) {
super(scope, id, props)
this.authorizerId = this.ref
}
}
Which can be used similar to the above example, as follows:
- import { AuthorizationType, CfnAuthorizer } from '@aws-cdk/aws-apigateway'
+ import { AuthorizationType } from '@aws-cdk/aws-apigateway'
import { UserPool } from '@aws-cdk/aws-cognito'
+ import { CustomNodeLambdaEndpoint } from './constructs/CustomNodeLambdaEndpoint'
const userPool = UserPool.fromUserPoolId(this, 'UserPool', userPoolId)
// ..snip..
- const cognitoAuthorizer = new CfnAuthorizer(this, 'CognitoAuthorizer', {
+ const cognitoAuthorizer = new CognitoApiGatewayAuthorizer(this, 'CognitoAuthorizer', {
name: 'CognitoAuthorizer',
type: AuthorizationType.COGNITO,
providerArns: [userPool.userPoolArn],
identitySource: 'method.request.header.Authorization',
restApiId: api.restApiId,
})
// ..snip..
Obviously this could be made 'nicer' by wrapping some of the required props into the 'wrapper' itself (eg. type
), but I was looking for the simplest/closest 'api' to using CfnAuthorizer
directly.
I noticed that @rrix also provided a more thorough TypeScript-based solution in https://github.com/aws/aws-cdk/issues/9023#issuecomment-658309644 which seems to implement authorizerId
/ support IAuthorizer
.
@nija-at Since there seems to be a decently solid looking implementation for this, I'm wondering if we could get an official version of it merged into CDK to save having to use these hacks/workarounds?
@nija-at Since there seems to be a decently solid looking implementation for this, I'm wondering if we could get an official version of it merged into CDK to save having to use these hacks/workarounds?
@0xdevalias - we absolutely can. This isn't prioritized on our end at the moment, but contributions are welcome 馃槉
Most helpful comment
@0xdevalias - we absolutely can. This isn't prioritized on our end at the moment, but contributions are welcome 馃槉