Cognito Auth Test Harness
This directory contains a test harness for validating AWS Cognito authentication and authorization with Go and the Echo web framework. It demonstrates a complete OAuth 2.0 flow with role-based access control (RBAC). It is temporary and will go away once the final middleware is in place.
Features
- Complete OAuth 2.0 authentication flow with AWS Cognito
- Role-based access control (RBAC) for API endpoints
- JWT token validation with signature verification
- Efficient JWKS caching to minimize external requests
- Debug mode for token inspection
Setup
Prerequisites
- Go 1.18 or higher
- AWS Cognito User Pool with configured app client
- Test user(s) in the Cognito User Pool with assigned groups
Environment Variables
Set the following environment variables before running the application:
export COGNITO_CLIENT_ID="552cqkf3640t39ncehkmgpce31"
export COGNITO_CLIENT_SECRET="your-client-secret"
export COGNITO_DOMAIN="us-east-21y6po8rr8.auth.us-east-2.amazoncognito.com"
export COGNITO_USER_POOL_ID="us-east-2_1y6po8rR8"
export AWS_REGION="us-east-2"
# Optional: Enable debug mode to see token details
export DEBUG="true"
Running the Application
- Build and run the server:
go run main.go
- The server will start on
http://localhost:8080
Testing the Authentication Flow
Step 1: Initial Login
- Open the following URL in your browser (update domain/client_id if different):
https://us-east-21y6po8rr8.auth.us-east-2.amazoncognito.com/login?client_id=552cqkf3640t39ncehkmgpce31&response_type=code&scope=email+openid+phone&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fquery
-
Log in with your Cognito user credentials
-
After successful authentication, Cognito will redirect to your local server (
/queryendpoint) -
You'll see a JSON response with:
- Authentication status
- User information (username, email)
- User groups
- JWT tokens (id_token and access_token)
Example response:
{
"authenticated": true,
"username": "testuser",
"email": "user@example.com",
"groups": ["uploaders", "querybuilders"],
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
Step 2: Testing Protected Endpoints
Use the obtained token to access protected endpoints:
-
Copy the
id_tokenvalue from the response -
Use it as a Bearer token in subsequent requests:
# Using curl to access a protected endpoint
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." http://localhost:8080/users
- Test authorization with different endpoints:
| Endpoint | Required Groups |
|---|---|
| /users | exporters |
| /users/:id | exporters, querybuilders |
| /orders | exporters |
| /reports/sales | exporters, uploaders, querybuilders |
| /settings | exporters |
| /query | exporters |
| /api/inventory/update | exporters, uploaders |
Note. If you want to change the RBAC requirements for the server they are completely table driven.
The code where they are defined (in main()) looks like this. Feel free to change them and rerun.
routePermissions := map[string][]string{
"/users": {"exporters"},
"/users/:id": {"exporters", "querybuilders"},
"/orders": {"exporters", "exporters"},
"/reports/sales": {"exporters", "uploaders", "querybuilders"},
"/settings": {"exporters"},
"/query": {"exporters", "querybuilders"}, // Only exporters can access /query
"/api/inventory/update": {"exporters", "uploaders"},
}
- If your user doesn't have the required group for an endpoint, you'll receive a 403 Forbidden response:
{
"error": "Insufficient permissions",
"message": "User doesn't have the required group membership",
"username": "testuser",
"groups": ["uploaders", "querybuilders"],
"required_groups": ["exporters"]
}
Authentication Flow Explained
Initial Login (OAuth 2.0 Flow)
- User Authentication: User authenticates with Cognito's hosted UI
- Authorization Code: Cognito redirects to
/query?code=...with an authorization code - Token Exchange: The server exchanges this code for OAuth tokens by calling Cognito's token endpoint
- Token Verification: The server verifies the JWT token signature using Cognito's JWKS
- Group Verification: The server checks if the user belongs to the required groups for the
/queryendpoint 6. Note that /query is just a placeholder and will be changes to something like /login or /login/callback in the api server. This setting is set in cognito on the user pool. - Response: If authorized, the server returns the tokens and user information; if not, it returns a 403 error
Subsequent API Requests
- Token Submission: Client includes the ID token as a Bearer token in the Authorization header
- Token Validation: Server validates the token's signature, expiration, and other claims
- Group Extraction: Server extracts the user's groups from the token
- Permission Check: Server checks if the user has any of the required groups for the requested endpoint
- Access Control: If authorized, the request proceeds to the handler; if not, a 403 error is returned
Advanced Features
JWKS Caching
The server caches the JSON Web Key Set (JWKS) used to verify token signatures, reducing the number of requests to AWS.
Debug Mode
Enable debug mode by setting the DEBUG environment variable to true. This will:
- Log decoded token claims
- Log raw tokens
- Provide more verbose logging throughout the authentication process
Integration into Your Own Application
This test harness is for proving the design of the echo middleware before attempting integration:
- The
TokenValidationMiddlewarehandles both authentication and authorization - The route permissions map can be configured to match our application's security requirements
- The JWKS caching mechanism ensures efficient token validation