Skip to content

Latest commit

 

History

History
143 lines (91 loc) · 9.1 KB

DeveloperDocumentation.md

File metadata and controls

143 lines (91 loc) · 9.1 KB

User Documentation / Client Developer Documentation / Developer Documentation

Developer Documentation

This document is for contributors of the project. Contribution are welcome see CONTRIBUTING for information and rules of contribution

Create your own dev environment

Follow the deployment instructions from the user documentation.

If you need a client, you can use the demo client project. But you should play with your browser and Postman for easier test of the flows.

Architecture

The project architecture is the following:

Project Architecture Image

Source code structure

This is a standard AWS Amplify & React project. It has been bootstrapped using Create React App and the dynamic configuration is injected by react app rewired.

Main code directories:

./src                           <-- code of the SPA
./public                        <-- static files
amplify/#current-cloud-backend  <-- current env (not in conf, in .gitignore)
amplify/backend                 <-- reference environment definition
amplify/backend/auth            <-- Cognito user pool configuration
amplify/backend/function        <-- all Lambda function code are here
amplify/backend/storage         <-- DynamoDB tables definition
amplify/backend/hosting         <-- specific Cloudfront and S3 setup
amplify/backend/kms             <-- contain the cryptographic material setup (for token encryption in DynamoDB)

Coding conventions

We use EditorConfig to apply coding conventions across the project. If you use VSCode, make sure to install this plugin for the editor to pick it up. If you use another IDE, I'm certain you'll find a corresponding plugin for it with a bit of googling.

After installing the plugin, every new file you create will follow the conventions setup over here: tabs with size 4, no trailing whitespace and with a final newline. These conventions have been chosen to match the Amplify framework coding conventions. You don't have to do anything else, but in case you want to make sure your document is properly formatted, you can call the "Format Document" in the commands palette

VSCode format document

Lambda functions

Oauth2/OIDC functions

  • amplifyIdentityBrokerAuthorize: Handle the Oauth2 flows. Is invoked behind the /oauth2/authorize path on the API Gateway

  • amplifyIdentityBrokerToken: Answer to /oauth2/token standard oauth calls.

  • amplifyIdentityBrokerUserInfo: Returns standard answer to /oauth2/userinfo. Needs a valid JWT token

  • amplifyIdentityBrokerExposeJWKS: Return the oauth public key used by Cognito. It is onvoked behind /.well-known/jwks.json

  • amplifyIdentityBrokerAccountConfirmation: This is mapped to /accountConfirmation path which is the link provided in confirmation emails. This activate the user account.

SPA backend functions

  • amplifyIdentityBrokerStorage: Is used by the SPA to store code_challenge and token temporarily during oauth flow execution.
  • amplifyIdentityBrokerVerifyClient: Is used by the SPA to check if a pair redirect_uri + client_id is valid. It looks in the DynamoDB table amplifyIdentityBrokerClientsTable to do so

Cognito Trigger functions

  • amplifyIdentityBrokerCustomMessage: Is invoked before sending any email to the user. It is associated to the Custom message Lambda Trigger of the Cognito user pool.
  • amplifyIdentityBrokerMigration: Is not invoked by default. This is just an example of how to do a migration. Can be associated to the Migrate user trigger
  • amplifyIdentityBrokerDefineAuthChallenge: Is invoked during the token swap operation (see detail in SSO Token Swap section). This one define the challenge execution order.
  • amplifyIdentityBrokerVerifyAuthChallenge: Is invoked during the token swap operation (see detail in SSO Token Swap section). This one validate the original token and return success if the username (sub, the Amazon Cognito ID) from the current flow is the same than the one in the token.
  • amplifyIdentityBrokerCreateAuthChallenge: Is invoked during the token swap operation (see detail in SSO Token Swap section). This does nothing but is required in a custom flow.

Utils functions

  • amplifyIdentityBrokerPostDeployment: Is a CloudFormation custom resources that depends on most of Api, Auth and all Functions. It receives the value of the hosting (the cloudfront domain) the UserPool ID and apps and update the configuration of Cognito app with callback that match. It also inject the HOSTING_DOMAIN environment variable for all functions. The domain value can be override in team-provider-info.json with hostingDomain (see user documentation). Also this domain is propagated to frontend by config-overrides.js

Implemented auth flows

Click to expand!

Flow entities are:

  • User: the user and his browser
  • Client Application: (like the one from our client demo project)
  • Identity Broker : the main project
  • DynamoDB: the broker storage layer
  • Cognito: The Cognito service and endpoints
  • Cognito Hosted UI: (not visible to the user)
  • Idp: Any 3rd party identity provider (in the case of federation)

PKCE flow

PKCE flow

Implicit flow

Implicit flow

Note: Accordingly to the what the Oauth2 BCP recommend we do not return the access_token in that flow but only the id_token.

IDP federation flow

IDP federation flow

Note: The end of the flow (the return to the AWS Amplify broker client will be done accordingly to the client selected flow: PKCE or Implicit)

SSO Token Swap

Every client application will get a token associated to the client_id he owns. Doing this makes sure that the tokens are distributed to the right OIDC Audience, and also allow users to customize the scope and list of IdP they want to activate for a given client.

When a login happens in the broker it is always done with a given client_id. This client_id maybe one from the client application the user came from, or the one of the broker if the user navigate directly to the broker domain. Once a user logs in, the broker stores the tokens (ID, access, refresh) in localstorage and in a cookie on the broker domain.

Now, if after a first successful login, the same user comes from another client application. Because of SSO he will be considered logged in but we cannot give him the current token since it is not a token matching with the client_id of the client application. Thanks to Amazon Cognito triggers and a custom auth flow; exchanging a token from one client_id to another this is possible.

This is the flow followed during this swap (here when coming from a PKCE client):

Token Swap PKCE flow

Note: It could have ben possible to reduce the complexity of this flow by relying on the Amazon Cognito hosted UI to swap the tokens. In fact the hosted UI will do the token SWAP if a user browser come back with an existing valid token in a cookie. We chose not relying on that because if for any reason the cookie is not there (on the hosted UI domain) the user will be presented the Amazon Cognito hosted UI which we want to absolutely prevent.

Contribute

PR are welcome. Any fixes or improvements. For new features, please open an issue to discuss it.

See CONTRIBUTING for more rules and information.

Please do not update team-provider-info.json in your Pull-Requests.

Pipelines

You are free to create your own pipeline for your environments. If you are an AWS employee, go to the internal wiki for details.