From 52877b74b06275e51439d9b37a04e78efdeb9f06 Mon Sep 17 00:00:00 2001 From: campionfellin Date: Fri, 28 Feb 2020 21:33:20 -0800 Subject: [PATCH] feat: Example of Cognito-protected APIGateway backed by Lambda Signed-off-by: campionfellin --- typescript/cognito-api-lambda/README.md | 60 +++++++++++++++++++ typescript/cognito-api-lambda/cdk.json | 3 + typescript/cognito-api-lambda/index.ts | 58 ++++++++++++++++++ typescript/cognito-api-lambda/package.json | 26 ++++++++ .../cognito-api-lambda/src/helloworld.ts | 7 +++ typescript/cognito-api-lambda/tsconfig.json | 21 +++++++ 6 files changed, 175 insertions(+) create mode 100644 typescript/cognito-api-lambda/README.md create mode 100644 typescript/cognito-api-lambda/cdk.json create mode 100644 typescript/cognito-api-lambda/index.ts create mode 100644 typescript/cognito-api-lambda/package.json create mode 100644 typescript/cognito-api-lambda/src/helloworld.ts create mode 100644 typescript/cognito-api-lambda/tsconfig.json diff --git a/typescript/cognito-api-lambda/README.md b/typescript/cognito-api-lambda/README.md new file mode 100644 index 000000000..ad3bbb55a --- /dev/null +++ b/typescript/cognito-api-lambda/README.md @@ -0,0 +1,60 @@ +# APIGateway backed by Lambda and protected by Cognito User Pools. + +--- + +![Stability: Stable](https://img.shields.io/badge/stability-Stable-success.svg?style=for-the-badge) + +> **This is a stable example. It should successfully build out of the box** +> +> This examples does is built on Construct Libraries marked "Stable" and does not have any infrastructure prerequisites to build. + +--- + + +This an example of an APIGateway that is protected with a Cognito User Pool, pointing to a Hello World Lambda. + +## Build + +To build this app, you need to be in this example's root folder. Then run the following: + +```bash +npm install -g aws-cdk +npm install +npm run build +``` + +This will install the necessary CDK, then this example's dependencies, and then build your TypeScript files and your CloudFormation template. + +## Deploy + +Run `cdk deploy`. This will deploy / redeploy your Stack to your AWS Account. + +After the deployment you will see the API's URL, which represents the url you can then use. + +## The Component Structure + +The whole component contains: + +- A Lambda Function that returns "Hello world!". +- An API with GET method that points to this Function. +- A Cognito User Pool +- An Authorizer for the API with the User Pool attached. + +## CDK Toolkit + +The [`cdk.json`](./cdk.json) file in the root of this repository includes +instructions for the CDK toolkit on how to execute this program. + +After building your TypeScript code, you will be able to run the CDK toolkits commands as usual: + + $ cdk ls + + + $ cdk synth + + + $ cdk deploy + + + $ cdk diff + diff --git a/typescript/cognito-api-lambda/cdk.json b/typescript/cognito-api-lambda/cdk.json new file mode 100644 index 000000000..cc2ccbdf8 --- /dev/null +++ b/typescript/cognito-api-lambda/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "node index" +} diff --git a/typescript/cognito-api-lambda/index.ts b/typescript/cognito-api-lambda/index.ts new file mode 100644 index 000000000..b8e6b1de4 --- /dev/null +++ b/typescript/cognito-api-lambda/index.ts @@ -0,0 +1,58 @@ +import { LambdaRestApi, CfnAuthorizer, LambdaIntegration, AuthorizationType } from '@aws-cdk/aws-apigateway'; +import { AssetCode, Function, Runtime } from '@aws-cdk/aws-lambda'; +import { App, Stack } from '@aws-cdk/core'; +import { UserPool, SignInType } from '@aws-cdk/aws-cognito' + +export class CognitoProtectedApi extends Stack { + constructor(app: App, id: string) { + super(app, id); + + // Function that returns 201 with "Hello world!" + const helloWorldFunction = new Function(this, 'helloWorldFunction', { + code: new AssetCode('src'), + handler: 'helloworld.handler', + runtime: Runtime.NODEJS_12_X + }); + + // Rest API backed by the helloWorldFunction + const helloWorldLambdaRestApi = new LambdaRestApi(this, 'helloWorldLambdaRestApi', { + restApiName: 'Hello World API', + handler: helloWorldFunction, + proxy: false, + }); + + // Cognito User Pool with Email Sign-in Type. + const userPool = new UserPool(this, 'userPool', { + signInType: SignInType.EMAIL + }) + + // Authorizer for the Hello World API that uses the + // Cognito User pool to Authorize users. + const authorizer = new CfnAuthorizer(this, 'cfnAuth', { + restApiId: helloWorldLambdaRestApi.restApiId, + name: 'HelloWorldAPIAuthorizer', + type: 'COGNITO_USER_POOLS', + identitySource: 'method.request.header.Authorization', + providerArns: [userPool.userPoolArn], + }) + + // Hello Resource API for the REST API. + const hello = helloWorldLambdaRestApi.root.addResource('HELLO'); + + // GET method for the HELLO API resource. It uses Cognito for + // authorization and the auathorizer defined above. + hello.addMethod('GET', new LambdaIntegration(helloWorldFunction), { + authorizationType: AuthorizationType.COGNITO, + authorizer: { + authorizerId: authorizer.ref + } + + }) + + } +} + + +const app = new App(); +new CognitoProtectedApi(app, 'CognitoProtectedApi'); +app.synth(); diff --git a/typescript/cognito-api-lambda/package.json b/typescript/cognito-api-lambda/package.json new file mode 100644 index 000000000..40fba6744 --- /dev/null +++ b/typescript/cognito-api-lambda/package.json @@ -0,0 +1,26 @@ +{ + "name": "cognito-api-lambda", + "version": "1.0.0", + "description": "Running an API Gateway using Cognito User Pool as an Authorizer for Hello World Lambda", + "private": true, + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "cdk": "cdk" + }, + "author": { + "name": "Campion Fellin " + }, + "license": "MIT", + "devDependencies": { + "@types/node": "^10.17.0", + "typescript": "~3.7.2" + }, + "dependencies": { + "@aws-cdk/aws-apigateway": "*", + "@aws-cdk/aws-cognito": "*", + "@aws-cdk/aws-dynamodb": "*", + "@aws-cdk/aws-lambda": "*", + "@aws-cdk/core": "*" + } +} diff --git a/typescript/cognito-api-lambda/src/helloworld.ts b/typescript/cognito-api-lambda/src/helloworld.ts new file mode 100644 index 000000000..f32ffe92a --- /dev/null +++ b/typescript/cognito-api-lambda/src/helloworld.ts @@ -0,0 +1,7 @@ +// Pretty basic Hello World lambda... + +export const handler = async (event: any = {}) : Promise => { + console.log(event); + + return { statusCode: 201, body: 'Hello world!' }; +}; diff --git a/typescript/cognito-api-lambda/tsconfig.json b/typescript/cognito-api-lambda/tsconfig.json new file mode 100644 index 000000000..f2e82ef87 --- /dev/null +++ b/typescript/cognito-api-lambda/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target":"ES2018", + "module": "commonjs", + "lib": ["es2016", "es2017.object", "es2017.string"], + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization":false + } +} +