Table of Contents
- Introduction
- What is AWS Cognito and How It Works
- How Cognito User Pool-based Authentication Works
- Authentication and Authorization in the Python Web App
- How the Python Web App Works
- Conclusion
Introduction
This blog delves into the basics of integrating AWS Cognito into a Python web application for user authentication. AWS Cognito offers a comprehensive solution for managing users, handling authentication (identity verification), and enabling access control (authorization) in a scalable and secure way. Through this guide, we will explore Cognito's User Pool, which serves as the foundation for managing user data and validating identities, as well as the processes of authentication and authorization.
Additionally, we will examine how Cognito's Hosted UI can simplify user login and when it might be more advantageous to implement a custom login interface to meet specific needs. The source code can be found at GitHub repository - Python Web App with AWS Cognito Auth.
What is AWS Cognito and How It Works
AWS Cognito is a service designed to manage authentication and authorization in web and mobile applications.
The core concept involves two key components:
- User Pools: This manages the user directory and provides authentication mechanisms. Users can sign up, sign in, and manage their profiles, with Cognito managing the complexity of secure user storage.
- Identity Pools: This provides authorization and federated identities. Once a user is authenticated (using Cognito or other identity providers like Google, Facebook), the identity pool issues temporary AWS credentials that allow them to access AWS resources such as S3, DynamoDB, or Lambda.
Understanding the distinction between authentication and authorization is key to using AWS Cognito effectively:
- Authentication: This process verifies who the user is. In AWS Cognito, the User Pool handles authentication. It confirms whether the user-provided credentials (like username and password or social login) are valid. After a successful login, Cognito issues JWT tokens (ID, Access, and Refresh tokens), which the application can use to identify and verify the user.
- Authorization: This process determines what actions the authenticated user is allowed to perform. After authentication, the Identity Pool issues temporary credentials that dictate what AWS resources the user can access. This step controls the scope of what the user is "authorized" to do.
How Cognito User Pool-based Authentication Works
AWS Cognito uses the User Pool to manage the entire lifecycle of users, from sign-up to sign-in, including the validation of identity.
Here’s an in-depth look at how it operates:
Step 1: User Registration
When a new user registers, their credentials (email, username, password) are stored securely in the User Pool. Cognito offers built-in mechanisms for verifying user identities via email or phone, enforcing password policies, and providing MFA (Multi-Factor Authentication).
Step 2: User Login
When a user logs in, Cognito checks the provided credentials against the stored records in the User Pool. Upon successful authentication, Cognito issues three tokens:
- ID Token: Contains user identity information (like user profile data). Used by the app to identify the user.
- Access Token: Grants access to specific resources. Can be used to control access to APIs, like in AWS API Gateway.
- Refresh Token: Allows the app to refresh the session without requiring the user to log in again.
Step 3: Token-based Authentication
These tokens are in JWT (JSON Web Token) format, allowing the application to validate them securely. The ID token and Access token are validated by checking their signatures and expiry times. The tokens enable stateless authentication, meaning you don’t need to store session data on the server.
Step 4: Token Handling in the Web App
The tokens are typically sent from the front-end to the back-end as part of the authorization header in each request. Here’s a typical flow:
- The user logs in and receives the tokens from Cognito.
- For each subsequent API call, the Access Token is included in the request headers.
- The server verifies the token and grants access based on the token's claims (which indicate the user's identity and what they are allowed to do).
Authentication and Authorization in the Python Web App
In the Python Web App with AWS Cognito Auth, the Python Flask app handles the authentication using Cognito’s APIs. Whether we are using the Hosted UI or a custom UI, the backend interacts with AWS Cognito to verify credentials and manage tokens.
Repo Branches for various Auth Usecases
There are 3 branches in the repo to handle various usecases:
secure-hosted-noui ( Custom Login UI )
In this scenario, we can build a login form. The web app captures the user credentials and sends them directly to Cognito’s authentication API. On success, Cognito responds with the necessary tokens, which we can store and use in the application.
secure-hosted-ui (Hosted UI)
Users are redirected to Cognito's pre-built login UI, which handles sign-up, sign-in, and password management. Once the user logs in, Cognito redirects back to the application with an authorization code. This code is then exchanged for an ID token, Access token, and Refresh token via AWS Cognito's token endpoint.
secure-hosted-ui-improved ( Hosted UI & Custom Login UI )
This branch combines both Hosted UI and custom login page.
- If the Hosted UI is configured, users are redirected to it for authentication.
- If the Hosted UI is not configured, the application shows its own login page.
This branch includes logic to handle both scenarios and logs the chosen authentication flow and login option.
When to Use Hosted UI
-
Quick Setup: If you're looking for a fast and easy solution to implement user login, the Hosted UI is the best option. It eliminates the need to build your own login form and manage complex authentication flows.
-
Pre-built OAuth Flows: Hosted UI comes with built-in support for OAuth2 flows like authorization code grants and implicit grants, which handle token exchanges seamlessly.
-
Secure, Best Practices Implemented: The Hosted UI follows security best practices like handling password resets, MFA, and token validation, all out of the box.
-
Social Sign-ins: Integrating third-party providers (e.g., Google, Facebook) is easier with the Hosted UI since AWS Cognito manages those authentication flows directly.
When Not to Use Hosted UI (Use Custom Login UI)
-
Full Control Over User Experience: If you need full customization of your login/signup pages to fit your app’s branding or design requirements, building a custom UI gives you total flexibility. The Hosted UI, while customizable to some degree, has limitations in terms of design and UX.
-
Advanced Authentication Logic: If your application requires more complex logic during login (such as custom CAPTCHA systems, special password policies, or biometric authentication), a custom UI is better suited to handle these cases.
-
Tighter Integration with Other Backends: A custom UI allows for more direct interaction between your app and the backend. This is ideal if you need to integrate custom workflows, user profile management, or data aggregation during the login process.
How the Python Web App Works
This Flask-based Python web app demonstrates how to integrate AWS Cognito for secure user authentication. The app offers two key features: authentication via Cognito Hosted UI and a custom login interface that interacts directly with the Cognito API. The app manages user management, login, and token-based authentication, showcasing how Cognito can be used in different scenarios.
Features of the Built App
Authentication Using Hosted UI: Users are redirected to the AWS Cognito Hosted UI for login and sign-up, simplifying the authentication process by offloading the UI management to Cognito.
Custom Login Interface:
- For use cases where full control over the user experience is required, the app also provides a custom login interface. This form captures the user's credentials (username and password) and interacts directly with AWS Cognito via backend APIs.
Token Management:
- Regardless of the authentication method (Hosted UI or Custom Login), the app manages JWT tokens (ID token and Access token) after a successful login.
- These tokens are stored in the session and are used for authorizing access to protected routes within the application.
- The ID token contains information about the authenticated user, and the Access token is used to authorize actions like API requests or access to resources.
Project preparation
Before running the app, ensure you have the following:
-
AWS Account with Cognito set up (User Pool, App Client, and Hosted UI configured).
-
Python 3.x installed on your local machine.
-
Flask and required Python dependencies installed (which are listed in the
requirements.txt
file). Install the dependencies by running:pip install -r requirements.txt
-
AWS Cognito Configurations: You need to configure the following values in your app:
- Cognito User Pool ID
- App Client ID
- Hosted UI Domain
- Region
These details can be stored in environment variables or directly in the application configuration file.
How to Run the App
- Clone the repository:
- Set up environment variables for AWS Cognito configuration:
- Run the Flask application:
The app should now be accessible at http://localhost:5000
.
Conclusion
AWS Cognito provides a powerful and flexible way to implement authentication in web applications. Its User Pools handle authentication (identity verification). The choice between using Cognito’s Hosted UI or building a custom login interface depends on our project’s needs. Hosted UI is ideal for quick setups with minimal development overhead, while a custom UI gives you the flexibility to create a tailored user experience. With the knowledge from this guide and the associated GitHub repository, we can confidently build secure, scalable authentication systems for our Python web apps.
Happy coding!! 👍 🎉