├── .gitignore ├── frontend ├── config-example.json ├── README.md └── index.html ├── package.json ├── handler.js ├── README.md └── serverless.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | .webpack 8 | -------------------------------------------------------------------------------- /frontend/config-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "serviceURL":"https://>.execute-api.eu-central-1.amazonaws.com/dev/hiUsers", 3 | "authenticationURL": "https:///login?response_type=token&client_id=&redirect_uri=http://localhost:3000" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cognito-user-pool", 3 | "version": "1.0.0", 4 | "description": "This service is in charge of managing user authentication and authorization in the MRV Platform. It consists of the following resources:", 5 | "main": "handler.js", 6 | "dependencies": { 7 | "http-server": "^0.11.1" 8 | }, 9 | "devDependencies": { 10 | "serverless-offline": "^4.4.0" 11 | }, 12 | "scripts": { 13 | "start": "http-server -o -p 3000 ./frontend", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "author": "", 17 | "license": "ISC" 18 | } 19 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.hiGuests = (event, context, callback) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: 'Hi! You are a guest' 8 | }), 9 | }; 10 | 11 | callback(null, response); 12 | }; 13 | 14 | module.exports.hiUsers = (event, context, callback) => { 15 | const response = { 16 | statusCode: 200, 17 | headers: { 18 | "Access-Control-Allow-Origin" : "http://localhost:3000", // Required for CORS support to work 19 | "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS 20 | }, 21 | body: JSON.stringify({ 22 | message: 'You are a registered user!' 23 | }), 24 | }; 25 | 26 | callback(null, response); 27 | }; 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless Cognito 2 | 3 | ## Setup 4 | 5 | 1. `serverless deploy` 6 | 7 | Besides deploying the service, we need to manually configure some details, since CloudFormation falls short. So, in the Cognito Dashboard, select the User Pool and follow the steps below: 8 | 9 | 1. Select "App client settings", enable Cognito User Pool as a provider and enter the callback and sign out URLs. Select "Implicit grant" as allowed OAuth flow and tick all the scopes 10 | 2. Select "Domain name" and create one 11 | 12 | ## Usage 13 | 14 | 1. Open a web browser and go to `https:///login?response_type=token&client_id=&redirect_uri=` 15 | 2. After loging in successfully, you'll be redirected to your calback URL with `id_token` in the query string 16 | 3. Put `id_token` in the `Authorization` HTTP header when submitting requests to the API 17 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | Example frontend code to use cognito auth to call a serverless service 2 | 3 | ## Prerequisites 4 | 5 | * Deploy the serverless service 6 | * Copy config-example.json to config.json 7 | * Edit the URLS. 8 | * ```serviceURL``` is the one is shown in the output of ```sls deploy``` and 9 | ```sls info``` if you already deployed earlier 10 | * For ``` authenticationURL``` you need to replace APP_CLIENT_ID which you get 11 | from the cognito console in "General settings / App Clients", and 12 | ```DOMAIN``` can be found under "App Integration" 13 | * Start the webserver via ```npm start``` one level above 14 | 15 | ## Usage 16 | 17 | * Go to the index page on http://localhost:3000 18 | * Authenticate by clicking on the authenticate link 19 | * Call the service by clicking the call service button 20 | 21 | ## TODO 22 | 23 | * Simplify code and usage: if no id_token is in url, immediately redirect to 24 | the authentication page! Manual authentication is not necessary. 25 | * Add a variant: use the cognito authentication endpoint instead of Cognito 26 | provided authentication frontend: 27 | https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html 28 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: cognito-user-pool 2 | 3 | provider: 4 | name: aws 5 | runtime: nodejs8.10 6 | region: eu-west-2 7 | stage: ${self:custom.currentStage} 8 | logRetentionInDays: 30 9 | timeout: 30 10 | 11 | custom: 12 | defaultStage: dev 13 | currentStage: ${opt:stage, self:custom.defaultStage} 14 | userPoolName: test-user-pool-${self:custom.currentStage} 15 | userPoolClientName: test-user-pool-client-${self:custom.currentStage} 16 | 17 | functions: 18 | registeredOnly: 19 | handler: handler.hiUsers 20 | events: 21 | - http: 22 | path: /hiUsers 23 | method: get 24 | authorizer: 25 | type: COGNITO_USER_POOLS 26 | authorizerId: 27 | Ref: ApiGatewayAuthorizer 28 | cors: 29 | origin: 'http://localhost:3000' 30 | headers: 31 | - Content-Type 32 | - X-Amz-Date 33 | - Authorization 34 | - X-Api-Key 35 | - X-Amz-Security-Token 36 | - X-Amz-User-Agent 37 | allowCredentials: true 38 | guests: 39 | handler: handler.hiGuests 40 | events: 41 | - http: 42 | path: /hiAll 43 | method: get 44 | 45 | resources: 46 | Resources: 47 | CognitoUserPool: 48 | Type: "AWS::Cognito::UserPool" 49 | Properties: 50 | MfaConfiguration: OFF 51 | UserPoolName: ${self:custom.userPoolName} 52 | UsernameAttributes: 53 | - email 54 | Policies: 55 | PasswordPolicy: 56 | MinimumLength: 6 57 | RequireLowercase: False 58 | RequireNumbers: True 59 | RequireSymbols: False 60 | RequireUppercase: True 61 | CognitoUserPoolClient: 62 | Type: "AWS::Cognito::UserPoolClient" 63 | Properties: 64 | ClientName: ${self:custom.userPoolClientName} 65 | GenerateSecret: False 66 | UserPoolId: 67 | Ref: CognitoUserPool 68 | ApiGatewayAuthorizer: 69 | DependsOn: 70 | - ApiGatewayRestApi 71 | Type: AWS::ApiGateway::Authorizer 72 | Properties: 73 | Name: cognito-authorizer 74 | IdentitySource: method.request.header.Authorization 75 | RestApiId: 76 | Ref: ApiGatewayRestApi 77 | Type: COGNITO_USER_POOLS 78 | ProviderARNs: 79 | - Fn::GetAtt: [CognitoUserPool, Arn] 80 | Outputs: 81 | CognitoUserPoolArn: 82 | Value: 83 | Fn::GetAtt: 84 | - CognitoUserPool 85 | - Arn 86 | Export: 87 | Name: CognitoUserPoolArn-${self:custom.currentStage} 88 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Cognito Authentication for Serverless example 6 | 7 | 93 | 94 | 95 | 96 | 97 | 98 |
99 |
Not authenticated
100 | Authenticate 101 |
102 | 103 | 104 |
105 | 106 | 109 | 110 |
111 | 112 | 113 | 114 | --------------------------------------------------------------------------------