Skip to main content

Shared Cognito authentication library for FastAPI + Jinja2 web apps

Project description

daylily-cognito

Shared AWS Cognito authentication library for FastAPI + Jinja2 web applications.

Installation

# Basic installation
pip install -e .

# With JWT verification support (recommended)
pip install -e ".[auth]"

# With development dependencies
pip install -e ".[dev,auth]"

Configuration

Option 1: Explicit Constructor

from daylily_cognito import CognitoConfig, CognitoAuth

config = CognitoConfig(
    name="myapp",
    region="us-west-2",
    user_pool_id="us-west-2_XXXXXXXXX",
    app_client_id="XXXXXXXXXXXXXXXXXXXXXXXXXX",
    aws_profile="my-profile",  # optional
)
config.validate()  # raises ValueError if invalid

auth = CognitoAuth(
    region=config.region,
    user_pool_id=config.user_pool_id,
    app_client_id=config.app_client_id,
    app_client_secret=config.app_client_secret,  # optional, for clients with secrets
    profile=config.aws_profile,
)

App Client Secret Support

When a Cognito app client has a client secret enabled, all authentication API calls require a SECRET_HASH parameter. The library automatically computes this when app_client_secret is provided:

# For app clients WITH a secret
auth = CognitoAuth(
    region="us-west-2",
    user_pool_id="us-west-2_pUqKyIM1N",
    app_client_id="your-client-id",
    app_client_secret="your-client-secret",  # Required for clients with secrets
)

# The SECRET_HASH is automatically computed as:
# base64(hmac_sha256(client_secret, username + client_id))

Note: If your Cognito app client was created with GenerateSecret=True, you MUST provide the app_client_secret parameter, otherwise authentication will fail with "Unable to verify secret hash for client".

Option 2: Namespaced Environment Variables

For multi-tenant or multi-environment setups:

export DAYCOG_PROD_REGION=us-west-2
export DAYCOG_PROD_USER_POOL_ID=us-west-2_abc123
export DAYCOG_PROD_APP_CLIENT_ID=client123
export DAYCOG_PROD_AWS_PROFILE=prod-profile  # optional
from daylily_cognito import CognitoConfig

config = CognitoConfig.from_env("PROD")

Option 3: Legacy Environment Variables

For backward compatibility with existing deployments:

export COGNITO_REGION=us-west-2        # or AWS_REGION, defaults to us-west-2
export COGNITO_USER_POOL_ID=us-west-2_abc123
export COGNITO_APP_CLIENT_ID=client123  # or COGNITO_CLIENT_ID
export AWS_PROFILE=my-profile           # optional
from daylily_cognito import CognitoConfig

config = CognitoConfig.from_legacy_env()

CLI Usage

The daycog CLI is the operational interface for Cognito management in this repo.

Shell Setup

Use the helper script so the venv/CLI are ready and shell env loading works:

source ./activate

This script:

  • creates/activates .venv
  • installs this repo editable
  • installs shell completion
  • defines a shell wrapper so daycog setup can export values into your current shell
  • loads the active context from ~/.config/daycog/config.yaml if present

Core Commands

# Show CLI help
daycog --help

# Check current Cognito config/status
daycog status

# Create pool + app client
daycog setup --name my-pool --port 8001 --profile my-aws-profile --region us-east-1

# Advanced setup (client name, callback/logout URLs, OAuth, MFA, tags, autoprovision)
daycog setup \
  --name my-pool \
  --client-name my-app-client \
  --domain-prefix my-pool \
  --callback-url http://localhost:8001/auth/callback \
  --logout-url http://localhost:8001/ \
  --oauth-flows code \
  --scopes openid,email,profile \
  --idp COGNITO \
  --mfa optional \
  --tags env=dev,owner=platform \
  --autoprovision \
  --profile my-aws-profile \
  --region us-east-1

# List all pools in a region
daycog list-pools --profile my-aws-profile --region us-east-1

# List apps (app clients) in a pool
daycog list-apps --pool-name my-pool --profile my-aws-profile --region us-east-1

# Add/update/remove apps in a pool
daycog add-app --pool-name my-pool --app-name web-app \
  --callback-url http://localhost:8001/auth/callback \
  --profile my-aws-profile --region us-east-1
daycog edit-app --pool-name my-pool --app-name web-app \
  --new-app-name web-app-v2 \
  --callback-url http://localhost:9000/auth/callback \
  --profile my-aws-profile --region us-east-1
daycog remove-app --pool-name my-pool --app-name web-app-v2 \
  --profile my-aws-profile --region us-east-1 --force

# Configure Google IdP for a pool/app from downloaded Google OAuth JSON
daycog add-google-idp --pool-name my-pool --app-name web-app \
  --google-client-json ./client_secret.json \
  --profile my-aws-profile --region us-east-1

# All-in-one: create pool/app and configure Google IdP in one command
daycog setup-with-google \
  --name my-pool \
  --client-name web-app \
  --callback-url http://localhost:8000/auth/google/callback \
  --google-client-json ./client_secret.json \
  --profile my-aws-profile --region us-east-1

# Delete one pool by name or ID
daycog delete-pool --pool-name my-pool --profile my-aws-profile --region us-east-1 --force
daycog delete-pool --pool-id us-east-1_abc123 --profile my-aws-profile --region us-east-1 --force
# If the pool has a Cognito Hosted UI domain, delete it automatically first
daycog delete-pool --pool-name my-pool --profile my-aws-profile --region us-east-1 --delete-domain-first --force

# User management
daycog list-users
daycog add-user user@example.com --password Secure1234
daycog set-password --email user@example.com --password NewPass123
daycog ensure-group lsmc-admins --description "Atlas admin group"
daycog add-user-to-group --email user@example.com --group lsmc-admins
daycog set-user-attributes --email user@example.com \
  --attribute custom:tenant_id=00000000-0000-0000-0000-000000000001 \
  --attribute custom:roles=ADMIN,INTERNAL_USER
daycog delete-user --email user@example.com --force
daycog delete-all-users --force
daycog export --output cognito_users.json

# Maintenance helpers
daycog fix-auth-flows
daycog setup-google --client-id YOUR_ID --client-secret YOUR_SECRET

# Legacy compatibility helper (prefer delete-pool)
daycog teardown --force

Command Status

Primary operational commands:

  • status
  • setup
  • config print
  • config create
  • config update
  • config create-all
  • list-pools
  • list-apps
  • add-app
  • edit-app
  • remove-app
  • add-google-idp
  • setup-with-google
  • delete-pool

Supported maintenance commands:

  • fix-auth-flows
  • list-users
  • add-user
  • ensure-group
  • add-user-to-group
  • set-user-attributes
  • set-password
  • delete-user
  • delete-all-users
  • export
  • setup-google

Legacy compatibility command:

  • teardown Prefer delete-pool. teardown is retained for older env-driven workflows that only know the active pool context.

setup Behavior

daycog setup resolves AWS context in this order:

  1. --profile, --region
  2. AWS_PROFILE, AWS_REGION

If either value is missing, setup exits with an error.

On success, setup writes/updates contexts in ~/.config/daycog/config.yaml:

  • <pool-id>.<region>
  • <pool-id>.<region>.<app-name>
  • the active context pointer

with:

  • AWS_PROFILE
  • AWS_REGION
  • COGNITO_REGION
  • COGNITO_USER_POOL_ID
  • COGNITO_APP_CLIENT_ID
  • COGNITO_CLIENT_NAME
  • COGNITO_CALLBACK_URL
  • COGNITO_LOGOUT_URL (when set)
  • COGNITO_DOMAIN (when Hosted UI domain is attached)

If you pass --print-exports, setup also prints shell export ... lines.

Additional setup options:

  • --client-name (default: <pool-name>-client)
  • --domain-prefix (default: pool name, used for Hosted UI domain)
  • --attach-domain/--no-attach-domain (default: attach domain)
  • --callback-url or --callback-path + --port
  • --logout-url
  • --generate-secret
  • --oauth-flows (comma-separated)
  • --scopes (comma-separated)
  • --idp (comma-separated)
  • --password-min-length
  • --require-uppercase/--no-require-uppercase
  • --require-lowercase/--no-require-lowercase
  • --require-numbers/--no-require-numbers
  • --require-symbols/--no-require-symbols
  • --mfa (off, optional, required)
  • --tags (key=value,key2=value2)
  • --autoprovision (reuse existing app client by --client-name when found)

Multi-App Contexts

For a single pool with multiple app clients, Daycog stores:

  • Pool context: <pool-id>.<region>
    • Last selected app context for that pool/region.
  • App context: <pool-id>.<region>.<app>
    • App-specific client settings (COGNITO_APP_CLIENT_ID, callback/logout, etc.).
  • Active context
    • The context loaded by activate.

daycog setup always writes the pool and app contexts and marks the app context active. daycog add-app / daycog edit-app always write the app context, and update pool/active context when --set-default is passed. daycog remove-app deletes the app in Cognito and, by default, removes the app context. daycog delete-pool removes matching pool/app contexts and clears the active context when it points at the deleted pool. If setup-target contexts already exist, daycog setup prints warnings and updates them in place.

Ownership Boundary

daycog is the operational owner for shared Cognito lifecycle:

  • user pool creation and updates
  • app client creation and callback/logout management
  • user creation
  • password resets and permanent password assignment
  • group creation and membership
  • user attribute updates such as custom:tenant_id and custom:roles

Service CLIs should treat daycog as the lower-level auth tool instead of re-implementing Cognito lifecycle operations locally.

Config File Commands

# Print active context and contents
daycog config print

# Print a specific pool context
daycog config print --pool-name my-pool --region us-east-1
daycog config print --pool-id us-east-1_abc123 --region us-east-1

# Create pool/app contexts from AWS and update the active context
daycog config create --pool-name my-pool --client-name web-app --profile my-aws-profile --region us-east-1
daycog config create --pool-id us-east-1_abc123 --client-id 4h57... --profile my-aws-profile --region us-east-1

# Update pool/app contexts from AWS and refresh the active context
daycog config update --pool-name my-pool --client-name web-app --profile my-aws-profile --region us-east-1

# Bootstrap one app context per client in a pool
daycog config create-all --pool-name my-pool --default-client atlas --profile my-aws-profile --region us-east-1

Multi-Config CLI Usage

Use --config NAME to select a named configuration:

export DAYCOG_PROD_REGION=us-west-2
export DAYCOG_PROD_USER_POOL_ID=us-west-2_prod
export DAYCOG_PROD_APP_CLIENT_ID=client_prod

export DAYCOG_DEV_REGION=us-east-1
export DAYCOG_DEV_USER_POOL_ID=us-east-1_dev
export DAYCOG_DEV_APP_CLIENT_ID=client_dev

daycog --config PROD status
daycog --config DEV list-users

Note: daycog config create/update use AWS lookups with --profile/--region (or AWS_*) and are separate from --config NAME. If a pool has app clients, config create/update sync the selected app into the pool context and set the active context to <pool-id>.<region>.<app>. If a pool has multiple app clients, config create/update require --client-name or --client-id; otherwise they fail and recommend config create-all. config create/update accept --callback-url / --logout-url to override the values written to Daycog contexts without mutating Cognito. config create-all creates missing app-scoped contexts for every client in the pool; it only updates the pool context and active context when --default-client is supplied. When using config print --pool-name or --pool-id, --region is required to resolve the region-scoped context name.

Maintenance Commands

daycog fix-auth-flows is a repair command for older clients missing ALLOW_ADMIN_USER_PASSWORD_AUTH.

daycog export writes the current pool's users to JSON for inspection or migration work:

daycog export --output cognito_users.json

daycog setup-google prints Google OAuth environment variables and the redirect URI to register. It does not update Cognito resources, so prefer add-google-idp or setup-with-google when you need operational changes.

FastAPI Integration

from fastapi import Depends, FastAPI
from daylily_cognito import CognitoAuth, CognitoConfig, create_auth_dependency

app = FastAPI()

# Load config and create auth handler
config = CognitoConfig.from_legacy_env()
auth = CognitoAuth(
    region=config.region,
    user_pool_id=config.user_pool_id,
    app_client_id=config.app_client_id,
)

# Create dependencies
get_current_user = create_auth_dependency(auth)
get_optional_user = create_auth_dependency(auth, optional=True)

@app.get("/protected")
def protected_route(user: dict = Depends(get_current_user)):
    return {"user": user}

@app.get("/public")
def public_route(user: dict | None = Depends(get_optional_user)):
    return {"user": user}

OAuth2 Helpers

from daylily_cognito import (
    build_authorization_url,
    build_logout_url,
    exchange_authorization_code,
)

# Build authorization URL for login redirect
auth_url = build_authorization_url(
    domain="myapp.auth.us-west-2.amazoncognito.com",
    client_id="abc123",
    redirect_uri="http://localhost:8000/auth/callback",
    state="csrf-token",
)

# Exchange authorization code for tokens
tokens = exchange_authorization_code(
    domain="myapp.auth.us-west-2.amazoncognito.com",
    client_id="abc123",
    code="auth-code-from-callback",
    redirect_uri="http://localhost:8000/auth/callback",
)

# Build logout URL
logout_url = build_logout_url(
    domain="myapp.auth.us-west-2.amazoncognito.com",
    client_id="abc123",
    logout_uri="http://localhost:8000/",
)

Google OAuth Integration

daylily-cognito supports standalone Google OAuth2 authentication that auto-creates users in your Cognito user pool. This hybrid approach lets users sign in with Google while keeping Cognito as the single user directory.

Prerequisites

  1. Create a Google Cloud project and enable the OAuth consent screen
  2. Create OAuth 2.0 credentials in the Google Cloud Console
  3. Register http://localhost:8000/auth/google/callback as an authorized redirect URI

Environment Variables

Namespaced:

export DAYCOG_PROD_GOOGLE_CLIENT_ID="your-google-client-id"
export DAYCOG_PROD_GOOGLE_CLIENT_SECRET="your-google-client-secret"

Legacy:

export GOOGLE_CLIENT_ID="your-google-client-id"
export GOOGLE_CLIENT_SECRET="your-google-client-secret"

Or use the CLI helper:

daycog setup-google --client-id YOUR_ID --client-secret YOUR_SECRET

Or configure Cognito Google federation directly:

daycog add-google-idp --pool-name my-pool --app-name web-app \
  --google-client-json ./client_secret.json \
  --profile my-aws-profile --region us-east-1

Or run all-in-one setup + Google IdP:

daycog setup-with-google \
  --name my-pool \
  --client-name web-app \
  --callback-url http://localhost:8000/auth/google/callback \
  --google-client-json ./client_secret.json \
  --profile my-aws-profile --region us-east-1

add-google-idp resolves Google credentials in this order:

  1. --google-client-id + --google-client-secret
  2. --google-client-json (web or installed keys)
  3. GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET
  4. DAYCOG_<NAME>_GOOGLE_CLIENT_ID + DAYCOG_<NAME>_GOOGLE_CLIENT_SECRET (when --config NAME is used)

Usage

from daylily_cognito import (
    build_google_authorization_url,
    exchange_google_code_for_tokens,
    fetch_google_userinfo,
    auto_create_cognito_user_from_google,
    generate_state_token,
    CognitoAuth,
    CognitoConfig,
)

# 1. Build authorization URL and redirect the user
state = generate_state_token()
auth_url = build_google_authorization_url(
    client_id="your-google-client-id",
    redirect_uri="http://localhost:8000/auth/google/callback",
    state=state,
)

# 2. In your callback handler, exchange the code for tokens
tokens = exchange_google_code_for_tokens(
    client_id="your-google-client-id",
    client_secret="your-google-client-secret",
    code=request.query_params["code"],
    redirect_uri="http://localhost:8000/auth/google/callback",
)

# 3. Fetch the user's Google profile
userinfo = fetch_google_userinfo(tokens["access_token"])
# userinfo contains: sub, email, email_verified, name, given_name,
#                    family_name, picture, locale, hd (if Google Workspace)

# 4. Auto-create or retrieve the Cognito user
config = CognitoConfig.from_legacy_env()
auth = CognitoAuth(
    region=config.region,
    user_pool_id=config.user_pool_id,
    app_client_id=config.app_client_id,
)
result = auto_create_cognito_user_from_google(auth, userinfo)
# result = {"user": {...}, "created": True/False, "google_sub": "...", "email": "..."}

Google Attributes Captured

All attributes available with standard scopes (openid email profile) — no extra permissions required:

Claim Description
sub Unique Google user ID
email Email address
email_verified Whether email is verified by Google
name Full display name
given_name First name
family_name Last name
picture Profile photo URL
locale User locale (BCP 47)
hd Hosted domain (Google Workspace only, absent for personal accounts)

Cognito Custom Attributes

The user pool must have these custom attributes configured:

  • custom:customer_id — defaults to Google sub
  • custom:google_sub — Google unique user ID
  • custom:google_hd — hosted domain (optional, populated when present)

Development

# Install with dev dependencies
pip install -e ".[dev,auth]"

# Run tests
pytest -q

# Run tests with coverage
pytest --cov=daylily_cognito

# Lint and format
ruff check daylily_cognito tests
ruff format daylily_cognito tests

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

daylily_cognito-0.1.31.tar.gz (80.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

daylily_cognito-0.1.31-py3-none-any.whl (48.9 kB view details)

Uploaded Python 3

File details

Details for the file daylily_cognito-0.1.31.tar.gz.

File metadata

  • Download URL: daylily_cognito-0.1.31.tar.gz
  • Upload date:
  • Size: 80.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for daylily_cognito-0.1.31.tar.gz
Algorithm Hash digest
SHA256 ccfb9e3badda0d51a9e20c7b014bddb67ffe75d2d566885d1e54169514307fad
MD5 ded52955e6467f11e75df65685c2b2df
BLAKE2b-256 68f7607db9499e7d9361f799decff62f8638ef8c8870c7798e3aa190efa24042

See more details on using hashes here.

File details

Details for the file daylily_cognito-0.1.31-py3-none-any.whl.

File metadata

File hashes

Hashes for daylily_cognito-0.1.31-py3-none-any.whl
Algorithm Hash digest
SHA256 ee2b316c145bcbc0a8511f80a34ac0d136771e93e7fea31b847f477d0b763621
MD5 4652b0957914fefd331a8b3b84bb717e
BLAKE2b-256 f4e7ff10db70b4f07b5807cae908806c8a66d744cc36ae9c09bc67255f36a2a3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page