Skip to content

Latest commit

 

History

History
400 lines (317 loc) · 8.85 KB

File metadata and controls

400 lines (317 loc) · 8.85 KB

Authentication Setup Guide

This guide covers setting up authentication for the Order API on different cloud providers.

AWS - Cognito User Pool Setup

1. Create Cognito User Pool

aws cognito-idp create-user-pool \
  --pool-name ecommerce-users \
  --policies "PasswordPolicy={MinimumLength=8,RequireUppercase=true,RequireLowercase=true,RequireNumbers=true}" \
  --auto-verified-attributes email \
  --schema Name=email,Required=true Name=tenant_id,AttributeDataType=String,Mutable=true \
  --region us-east-1

2. Add Custom Attribute for Tenant ID

In the AWS Console:

  1. Go to Cognito User Pools
  2. Select your pool
  3. Go to "Attributes"
  4. Add custom attribute: custom:tenant_id (String, Mutable)

3. Create App Client

aws cognito-idp create-user-pool-client \
  --user-pool-id <your-pool-id> \
  --client-name order-api-client \
  --explicit-auth-flows ALLOW_USER_PASSWORD_AUTH ALLOW_REFRESH_TOKEN_AUTH \
  --read-attributes email custom:tenant_id \
  --region us-east-1

4. Create Test User

# Create user
aws cognito-idp admin-create-user \
  --user-pool-id <your-pool-id> \
  --username testuser@example.com \
  --user-attributes Name=email,Value=testuser@example.com Name=email_verified,Value=true \
  --temporary-password TempPass123! \
  --region us-east-1

# Set tenant_id
aws cognito-idp admin-update-user-attributes \
  --user-pool-id <your-pool-id> \
  --username testuser@example.com \
  --user-attributes Name=custom:tenant_id,Value=tenant-123 \
  --region us-east-1

# Set permanent password
aws cognito-idp admin-set-user-password \
  --user-pool-id <your-pool-id> \
  --username testuser@example.com \
  --password MySecurePass123! \
  --permanent \
  --region us-east-1

5. Get Authentication Token

# Using AWS CLI
aws cognito-idp initiate-auth \
  --auth-flow USER_PASSWORD_AUTH \
  --client-id <your-app-client-id> \
  --auth-parameters USERNAME=testuser@example.com,PASSWORD=MySecurePass123! \
  --region us-east-1

# Extract the IdToken from the response

6. Test API with Token

TOKEN="<IdToken-from-previous-step>"
API_URL="<your-api-gateway-url>"

curl -X POST $API_URL/orders \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_name": "John Doe",
    "customer_email": "john@example.com",
    "total_amount": 99.99,
    "items": [
      {
        "product_name": "Test Product",
        "quantity": 1,
        "unit_price": 99.99
      }
    ]
  }'

Sample Claims Structure

When properly configured, your API will receive claims like:

{
  "sub": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "email": "testuser@example.com",
  "email_verified": true,
  "custom:tenant_id": "tenant-123",
  "aud": "your-app-client-id",
  "token_use": "id",
  "auth_time": 1234567890,
  "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX",
  "exp": 1234571490,
  "iat": 1234567890
}

Azure - Azure AD B2C Setup

1. Create Azure AD B2C Tenant

# Create resource group
az group create --name ecommerce-rg --location eastus

# Create B2C tenant (do this in Azure Portal)
# Portal -> Create a resource -> Azure Active Directory B2C

2. Configure Custom Claims

In Azure Portal:

  1. Go to Azure AD B2C
  2. User attributes -> Add custom attribute
  3. Name: tenant_id, Data Type: String

3. Create User Flow

  1. User flows -> New user flow
  2. Sign up and sign in
  3. Collect attributes: Email, tenant_id
  4. Return claims: Email, tenant_id, Object ID

4. Register Application

# In Azure Portal
# App registrations -> New registration
# Redirect URI: https://your-function-app.azurewebsites.net/.auth/login/aad/callback

# After registration, note:
# - Application (client) ID
# - Directory (tenant) ID

5. Configure Azure Function Authentication

az functionapp auth update \
  --name your-function-app \
  --resource-group ecommerce-rg \
  --enabled true \
  --action LoginWithAzureActiveDirectory \
  --aad-client-id <your-app-client-id> \
  --aad-token-issuer-url https://login.microsoftonline.com/<tenant-id>/v2.0

6. Test Azure Function

# Get token using OAuth2 flow
# Then call function
curl -X POST https://your-function-app.azurewebsites.net/api/orders \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @test_order.json

GCP - Firebase Authentication

1. Create Firebase Project

# In Firebase Console
# console.firebase.google.com
# Create new project or select existing

2. Enable Authentication

# In Firebase Console:
# Authentication -> Sign-in method
# Enable Email/Password

3. Add Custom Claims (Server-Side)

Create a Cloud Function to set custom claims:

// setClaims.js
const admin = require('firebase-admin');
admin.initializeApp();

exports.setTenantClaim = async (uid, tenantId) => {
  await admin.auth().setCustomUserClaims(uid, {
    tenant_id: tenantId
  });
};

4. Create Test User

# Using Firebase CLI
firebase auth:import users.json --project your-project-id

users.json:

{
  "users": [
    {
      "uid": "user123",
      "email": "test@example.com",
      "passwordHash": "...",
      "customClaims": {
        "tenant_id": "tenant-123"
      }
    }
  ]
}

5. Configure API Gateway

# Create API Gateway
gcloud api-gateway apis create order-api

# Configure authentication
# In openapi.yaml, add security scheme:

openapi.yaml:

securityDefinitions:
  firebase:
    authorizationUrl: ""
    flow: "implicit"
    type: "oauth2"
    x-google-issuer: "https://securetoken.google.com/YOUR_PROJECT_ID"
    x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com"
    x-google-audiences: "YOUR_PROJECT_ID"

paths:
  /orders:
    post:
      security:
        - firebase: []

6. Get Firebase Token

// Client-side code
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';

const auth = getAuth();
const userCredential = await signInWithEmailAndPassword(
  auth,
  'test@example.com',
  'password123'
);
const token = await userCredential.user.getIdToken();

// Use token in API requests
fetch('https://your-api-url/orders', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(orderData)
});

Testing Authentication Locally

Mock Authentication for Development

Create a test script that simulates authenticated requests:

# test_auth.py
import requests
import json

# For local testing, bypass auth temporarily
# or use a mock token

def test_create_order():
    # In production, get real token from auth provider
    token = "mock-token-for-testing"
    
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }
    
    order_data = {
        "customer_name": "Test User",
        "customer_email": "test@example.com",
        "total_amount": 99.99,
        "items": [
            {
                "product_name": "Test Product",
                "quantity": 1,
                "unit_price": 99.99
            }
        ]
    }
    
    response = requests.post(
        "http://localhost:3000/orders",
        headers=headers,
        json=order_data
    )
    
    print(f"Status: {response.status_code}")
    print(f"Response: {response.json()}")

if __name__ == "__main__":
    test_create_order()

Security Best Practices

  1. Token Validation

    • Always validate tokens on the server
    • Check token expiration
    • Verify token signature
    • Validate issuer
  2. Tenant Isolation

    • Extract tenant_id from verified claims only
    • Never accept tenant_id from request body
    • Filter all queries by tenant_id
  3. HTTPS Only

    • Enforce HTTPS in production
    • Use secure headers
    • Enable CORS appropriately
  4. Rate Limiting

    • Implement rate limiting per user/tenant
    • Use API Gateway/Azure APIM features
  5. Logging

    • Log authentication failures
    • Monitor for suspicious patterns
    • Never log tokens or passwords

Troubleshooting

Common Issues

  1. "Missing tenant_id in claims"

    • Verify custom attribute is configured
    • Check token includes custom claims
    • Decode JWT to inspect claims
  2. "Invalid token"

    • Check token hasn't expired
    • Verify token is for correct client
    • Ensure token is ID token, not access token
  3. "401 Unauthorized"

    • Verify Bearer token format
    • Check API Gateway authorizer is configured
    • Validate token issuer matches configuration

Debug Tools

Decode JWT token:

# Using jwt.io or
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq

Test token validity:

# AWS
aws cognito-idp get-user --access-token $ACCESS_TOKEN

# Verify claims
python -c "import jwt; print(jwt.decode('$TOKEN', options={'verify_signature': False}))"