Skip to main content

Flow: Login & Authentication

How users authenticate and how subsequent API requests are authorized.

Request Path: Login

Request Path: Authenticated API Call

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 ExceptionPublic 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

SymptomWhere 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 401Auth Lambda logs. Token expired? JWKS fetch failing? Token in wrong header (must be x-api-key, not Authorization)?
API calls returning 403Auth Lambda logs. User not member of requested account?
Slow authAuth Lambda provisioned concurrency cold starts. JWKS cache miss.
Google SSO brokenCognito 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.