Skip to content

Flow: Login & Authentication

How users authenticate and how subsequent API requests are authorized.

Request Path: Login

graph TD
    A["Browser (Console React app)"]

    subgraph gw["API Gateway (Console API, anonymous route)"]
        subgraph ecs["Monolith ECS (BFF Console)"]
            B["Cognito: initiate_auth (USER_PASSWORD_AUTH)"]
            C["JWT access_token + refresh_token + id_token"]
        end
    end

    D["Browser stores token in cookie"]

    A --> B
    B --> C
    C -->|returns access_token| D

Request Path: Authenticated API Call

graph TD
    A["Browser"]

    subgraph gw["API Gateway (Console API, authenticated route)"]
        subgraph auth["Custom Authorizer Lambda (ControllerAuthLambda-{env})"]
            B["Verify JWT signature against Cognito JWKS"]
            C["Extract system_account_id from claims/membership"]
            D["Allow/Deny policy"]
        end
        E["VPC Link → NLB → Monolith ECS"]
    end

    F["Response"]

    A --> B
    B --> C
    C --> D
    D --> E
    E --> F

Step-by-Step: Login

1. Browser → Signin Endpoint

Where: API Gateway {env}-ConsoleApi, route POST /api/account/signin (anonymous — no auth required)

Input: email, password (8+ chars, 1 upper, 1 lower, 1 number, 1 special).

2. Cognito Authentication

Where: components/identity_service/backends/identity_aws.py

cognito_idp.initiate_auth(
    AuthFlow="USER_PASSWORD_AUTH",
    AuthParameters={"USERNAME": email, "PASSWORD": password, "SECRET_HASH": hmac_hash}
)

Returns AccessToken, RefreshToken, IdToken.

Error patterns:

Cognito Exception Public Message
UserNotFoundException "Incorrect email or password"
NotAuthorizedException "Incorrect email or password"
UserNotConfirmedException "User has not confirmed their email"

Inspect: Check Cognito user status — see Cognito.

3. Token Storage

Frontend stores access token in a cookie (config.tokenStorageName). API Gateway maps the token to the x-api-key header in the Lambda event (regardless of how the frontend sends it).

Step-by-Step: API Authorization

4. Custom Authorizer Lambda

Where: ControllerAuthLambda-{env} (provisioned concurrency: 5)

File: components/auth_lambda/authentication/lambda_handler.py

Both JWT tokens and API keys arrive via the same header: x-api-key (API Gateway maps the Authorization: Bearer header to x-api-key in the Lambda event).

Path A — JWT Bearer Token (value starts with "Bearer "):

  1. Strip "Bearer " prefix from the x-api-key header value
  2. Fetch JWKS from https://cognito-idp.{region}.amazonaws.com/{pool_id}/.well-known/jwks.json (cached 1hr)
  3. Verify RSA signature, check exp claim, validate client_id matches
  4. Fetch user from Cognito → extract system_account_id from custom attributes or membership lookup

Path B — API Key (value does NOT start with "Bearer "):

  1. Take raw value from x-api-key header
  2. DES3 decrypt → extract system_account_id, cell_id
  3. Validate against /key/validate endpoint

Inspect: Check auth Lambda logs — see Lambda.

aws logs tail /aws/lambda/ControllerAuthLambda-{env} --since 15m

5. BFF Console Authorizer (Secondary Layer)

Where: components/bff_console/bff_console/auth/authorizer.py

After the API Gateway authorizer allows the request:

  1. Validates token again (extracts username, email)
  2. Queries UsersAccountsService for account membership
  3. Verifies user is ACTIVE member of the requested account
  4. Enriches request with: cell_id, system_account_id, visible_account_id, role

Google SSO Login

  1. Browser redirects to Cognito hosted UI → Google OAuth
  2. Google authenticates → callback to Cognito
  3. DefineAuthChallenge Lambda immediately issues tokens (CUSTOM_AUTH flow)
  4. Cognito returns tokens via OAuth callback URL
  5. Frontend stores token, same as password login

Logout

POST /api/account/logoutcognito_idp.global_sign_out() → invalidates all tokens. Frontend clears cookie.

What to Look For

Symptom Where to Check
Login failing (wrong credentials) Cognito user status. Is user CONFIRMED? Is email_verified=true?
Login failing (500) Monolith ECS logs. Cognito service health.
API calls returning 401 Auth Lambda logs. Token expired? JWKS fetch failing? Token in wrong header (must be x-api-key, not Authorization)?
API calls returning 403 Auth Lambda logs. User not member of requested account?
Slow auth Auth Lambda provisioned concurrency cold starts. JWKS cache miss.
Google SSO broken Cognito Google IDP config. PreSignUp Lambda logs. OAuth callback URLs.
"User has not confirmed email" User in UNCONFIRMED state. Resend confirmation or admin-confirm.

Metrics

Auth Lambda publishes to CloudWatch:

  • auth_lambda_success — successful auth
  • authentication_error — auth-specific failure
  • auth_lambda_forbidden — 403 access denied
  • auth_lambda_5xx — internal error

Inspect: CloudWatch dashboard CloudControllerDashboard-{env} — see CloudWatch.