Skip to content
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

feat(newex): example of Cognito-protected APIGateway backed by Lambda #252

Merged
merged 1 commit into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions typescript/cognito-api-lambda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# APIGateway backed by Lambda and protected by Cognito User Pools.
<!--BEGIN STABILITY BANNER-->
---

![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.

---
<!--END STABILITY BANNER-->

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
<list all stacks in this program>

$ cdk synth
<generates and outputs cloudformation template>

$ cdk deploy
<deploys stack to your account>

$ cdk diff
<shows diff against deployed stack>
3 changes: 3 additions & 0 deletions typescript/cognito-api-lambda/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "node index"
}
58 changes: 58 additions & 0 deletions typescript/cognito-api-lambda/index.ts
Original file line number Diff line number Diff line change
@@ -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();
26 changes: 26 additions & 0 deletions typescript/cognito-api-lambda/package.json
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>"
},
"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": "*"
}
}
7 changes: 7 additions & 0 deletions typescript/cognito-api-lambda/src/helloworld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Pretty basic Hello World lambda...

export const handler = async (event: any = {}) : Promise <any> => {
console.log(event);

return { statusCode: 201, body: 'Hello world!' };
};
21 changes: 21 additions & 0 deletions typescript/cognito-api-lambda/tsconfig.json
Original file line number Diff line number Diff line change
@@ -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
}
}