πŸ“… Week 1 β€’ Day 05

Exploring Running Services

Now that your environment is set up, let's explore the running services. Learn to access admin interfaces, check health endpoints, view logs, and debug common issues.

⏱️Duration: ~1 hour
πŸ“ŠLevel: Hands-on
🎯Focus: Exploration

🎯 Learning Objectives

By the end of today's session, you will be able to:

🌐 Service Endpoints Directory

Here's your comprehensive guide to all EmpowerNow service endpoints:

πŸšͺ
BFF Gateway
Port 8000
πŸ”
IdP Service
Port 8002
βš–οΈ
PDP Service
Port 8001
πŸ‘₯
Membership
Port 8003
πŸ–₯️
IdP Admin UI
Port 80
πŸ“Š
Grafana
Port 3000
πŸ“ˆ
Prometheus
Port 9090
πŸ•ΈοΈ
Neo4j Browser
Port 7474

πŸ”„ The Life of a Request

Let's follow Alice as she logs into EmpowerNow. Her browser sends a request, but what happens next? Understanding this flow is the key to debugging any issue you'll ever encounter in this platform.

When Alice clicks "Login", a carefully choreographed dance begins between services. Each service plays a specific role, and if any one of them stumbles, the whole flow breaks. Let's trace the journey step by step.

Alice's Login Journey Through EmpowerNow
sequenceDiagram participant Browser as Alice's Browser participant BFF as BFF Gateway participant IdP as Identity Provider participant PDP as Policy Decision Point participant Redis as Session Store Browser->>BFF: GET /login Note over BFF: Starts OAuth flow BFF->>IdP: Redirect to /authorize Note over IdP: Shows login page IdP->>IdP: Authenticate Alice IdP->>BFF: Authorization code BFF->>IdP: Exchange code for tokens IdP-->>BFF: Access + Refresh tokens BFF->>Redis: Store session BFF->>PDP: Check Alice's permissions PDP-->>BFF: PERMIT BFF-->>Browser: Welcome, Alice!

Why does this matter? When something goes wrong, knowing this flow helps you pinpoint exactly where the problem is. Is the BFF not reaching IdP? Is PDP returning DENY? Is Redis failing to store the session? Each symptom points to a specific part of this journey.

πŸ§ͺ Try It: Follow a Request in Real-Time

Open your browser's Developer Tools (F12), go to the Network tab, then use this runner. Watch how each request flows through the system:

πŸ’š Health Checks

πŸ”§ Core service verification is automated using your organization’s deployment procedures and approved automation.

All EmpowerNow services expose health endpoints. Test them interactively:

πŸ§ͺ Try It: Check All Service Health

Click each button to verify the service is running and healthy:

BFF Gateway
Identity Provider (IdP)
Policy Decision Point (PDP)
Membership Service
Alternative: PowerShell curl
❯ curl https://idp.self.empowernow.ai/health
{ "status": "healthy", "version": "1.2.0", "checks": { "database": "healthy", "redis": "healthy" } }

Quick Health Check Script

PowerShell
# Quick health check for all services $services = @( "https://bff.self.empowernow.ai/health", "https://idp.self.empowernow.ai/health", "https://pdp.self.empowernow.ai/health", "https://membership.self.empowernow.ai/health" ) foreach ($url in $services) { try { $response = Invoke-WebRequest -Uri $url -TimeoutSec 5 Write-Host "βœ… $url - $($response.StatusCode)" -ForegroundColor Green } catch { Write-Host "❌ $url - FAILED" -ForegroundColor Red } }

πŸ” Become a Log Detective

It's Monday morning. Users are complaining they can't login. Your mission: find the culprit. Your weapon? The logs. Let's learn to read the clues.

Every request that flows through EmpowerNow leaves a trail. These logs are structured as JSON, making them both machine-readable and human-searchable. The key to becoming a great debugger is learning to follow these trails.

Understanding the Clues

Here's what a typical log entry looks like. Each field tells you something important:

πŸ“‹ EXHIBIT A: A Typical Log Entry
{ "event": "bff_request_error",← What happened "correlation_id": "abc-123-def",← Your tracking number "error": "upstream_timeout",← The smoking gun "path": "/api/oidc/token",← Where it happened "level": "error"← Severity }

The Golden Thread: Correlation ID

The correlation_id is your best friend. When a request enters the BFF, it gets assigned a unique ID that follows it through every service it touches. If you have a failing request, grab its correlation ID and you can trace its entire journey.

Following a Correlation ID Across Services
flowchart LR subgraph trace [correlation_id: abc-123-def] A[BFF Log Entry] --> B[IdP Log Entry] B --> C[PDP Log Entry] C --> D[Redis Log Entry] end style trace fill:transparent,stroke:#00d9ff

Key Events to Watch For

Not all log events are created equal. Here are the ones that usually point to problems:

Your Detective Toolkit

View All Logs

Commands
# All services (can be overwhelming) docker compose logs # Follow logs in real-time docker compose logs -f # Last 50 lines per service docker compose logs --tail 50

Service-Specific Logs

Commands
# IdP service logs docker compose logs -f idp # BFF service logs docker compose logs -f bff # Multiple services docker compose logs -f idp pdp bff # Filter with grep docker compose logs idp | grep ERROR docker compose logs pdp | grep "policy evaluation"

Pro Detective Techniques

Advanced Filtering
# Find all errors across all services docker compose logs | grep '"level":"error"' # Follow a specific correlation ID through the system docker compose logs --tail 5000 | grep "abc-123-def" # Watch for authentication failures in real-time docker compose logs -f idp | grep -E "401|403|invalid" # Find slow requests (look for high latency_ms values) docker compose logs bff | grep "latency_ms" | grep -E "[0-9]{4,}"
πŸ§ͺ Detective Exercise: Trace a Request

1. Run this health check and note the response headers
2. Look for X-Correlation-ID in the response
3. Use docker compose logs | grep "YOUR_CORRELATION_ID" to trace it

πŸ’œ
Use Dozzle for Better Logs

If you started the monitoring profile, access dozzle.self.empowernow.ai for a web-based log viewer with filtering and search. It's like having X-ray vision for your containers.

πŸ”§ When Things Go Wrong

Every developer has that moment: you start the services, but something isn't working. Don't panic. Let's walk through the most common issues you'll encounter, told as case studies from real debugging sessions.

Think of debugging as detective work. Each symptom is a clue, and your job is to follow the evidence to find the culprit. Here are the cases you're most likely to encounter.

πŸ”„
Case #1: The Restarting BFF
Container enters restart loop on startup
The Symptom

You run docker compose ps and see the BFF container status showing "Restarting" over and over. The health check never passes.

The Investigation

Check the BFF logs: docker compose logs bff --tail 50

You'll likely see: "Failed to load DCR secret" or "CSRF secret key required"

The Culprit

The BFF needs certain secrets to exist before it can start. These are typically created by bootstrap scripts that weren't run.

The Fix

Run the initialization script from the Deployment folder:

./scripts/create-idp-admin-jwt-secret.ps1

Then restart: docker compose restart bff

⏱️
Case #2: The Silent PDP
Authorization requests timeout
The Symptom

Users can login, but then see a spinning loader forever. The BFF logs show "upstream_timeout" when calling PDP.

The Investigation

The timeout happens because PDP can't respond. Check why:

docker compose logs pdp --tail 50

Also check Neo4j: docker compose logs neo4j --tail 20

The Culprit

PDP depends on Neo4j for policy storage. If Neo4j isn't ready, PDP can't answer authorization queries. This creates a cascade: BFF waits for PDP, PDP waits for Neo4j.

sequenceDiagram participant BFF participant PDP participant Neo4j BFF->>PDP: Check permission PDP->>Neo4j: Query policy Neo4j--xPDP: Connection refused Note over PDP: Waiting... timeout PDP--xBFF: 503 Service Unavailable
The Fix

Wait for Neo4j to be fully healthy: docker compose ps neo4j

If it's stuck, restart it: docker compose restart neo4j

Then restart PDP: docker compose restart pdp

πŸ”
Case #3: The 401 Mystery
Token requests return "invalid_client"
The Symptom

You call the token endpoint and get 401 Unauthorized with "error": "invalid_client". Your client credentials worked yesterday!

The Investigation

First, verify the client exists by checking the discovery endpoint:

curl https://idp.../api/oidc/.well-known/openid-configuration

Then check if your token's kid matches what IdP publishes:

curl https://idp.../api/oidc/.well-known/jwks.json | jq '.keys[].kid'
The Culprit

Usually one of: (1) Client was deleted/recreated with new credentials, (2) TOKEN_KEY_ID config doesn't match the actual key, or (3) Database was reset.

The Fix

If the client is missing, re-register it via DCR (see the DCR section below).

If keys don't match, check TOKEN_KEY_ID in env/services/idp.env.

🌐
Case #4: The Missing Hosts
Browser can't reach service URLs
The Symptom

You navigate to https://idp.self.empowernow.ai and get "This site can't be reached" or DNS errors.

The Investigation

Try pinging the hostname: ping idp.self.empowernow.ai

If it fails, the hostname isn't resolving.

The Culprit

These are local development domains that need to be in your hosts file. Without them, your browser doesn't know to look at localhost.

The Fix

Edit your hosts file and add the entries below. Windows: C:\Windows\System32\drivers\etc\hosts (open as Administrator). macOS/Linux: /etc/hosts (e.g. sudo nano /etc/hosts).

127.0.0.1 idp.self.empowernow.ai bff.self.empowernow.ai pdp.self.empowernow.ai

See Day 02 for the complete hosts file setup.

πŸ’Ύ
Case #5: The Redis Riddle
Sessions not persisting, random logouts
The Symptom

Users login successfully but are immediately logged out on the next request. Or sessions seem to "forget" they're authenticated.

The Investigation

Check Redis connectivity from BFF:

docker exec bff_app wget -qO- http://localhost:8000/health | jq '.checks.redis'

Also verify Redis is running: docker compose ps redis

The Culprit

BFF stores sessions in Redis. If Redis isn't reachable, sessions can't be stored or retrieved. This usually means Redis didn't start, or there's a network/password mismatch.

The Fix

Test Redis directly: docker exec redis redis-cli ping (should return PONG)

If that works, check REDIS_URL in BFF config matches the actual Redis host.

πŸ› οΈ Hands-on Labs

Theory is great, but nothing beats getting your hands dirty. These labs are designed to take you through real scenarios you'll encounter daily. Set aside about 30 minutes to work through them all.

Lab 1: The Complete Service Discovery Tour (10 minutes)

In this lab, you'll systematically explore every running service, understand what it does, and verify it's working correctly.

Step 1: Check What's Running

First, let's see the current state of your environment:

PowerShell
# See all containers and their status docker compose ps # Expected output should show services like: # NAME STATUS PORTS # bff_app Up (healthy) 0.0.0.0:8000->8000/tcp # idp_app Up (healthy) 0.0.0.0:8002->8002/tcp # pdp_app Up (healthy) 0.0.0.0:8001->8001/tcp # ...
βœ…
Self-Check

Count the services. Do you see at least 5 containers with "Up (healthy)" status? If any show "Restarting" or "Exit", that's a problem to investigate.

Step 2: Visit Each Service

Open each URL in your browser and note what you see:

  1. BFF Gateway - https://bff.self.empowernow.ai/health β€” Should return JSON with "healthy" status
  2. IdP - https://idp.self.empowernow.ai/api/oidc/.well-known/openid-configuration β€” Should return OIDC discovery document
  3. PDP - https://pdp.self.empowernow.ai/health β€” Should return health status
  4. IdP Admin UI - https://authn.self.empowernow.ai β€” Should show login page
πŸ§ͺ Try It: Explore the OIDC Discovery Document

This document tells clients everything they need to know about the IdP. Look for token_endpoint, authorization_endpoint, and scopes_supported:

βœ…
Self-Check Questions

From the discovery document, can you answer:

  • What is the token endpoint URL?
  • What scopes are supported?
  • What grant types can you use?
  • Where do you find the public keys (JWKS)?

Lab 2: The Authentication Flow (10 minutes)

Now let's actually authenticate. You'll get a token, decode it, and understand what's inside.

Step 1: Get an Access Token

Use client credentials to get a token (this simulates a backend service authenticating):

πŸ§ͺ Get Your Token

Click Send and copy the access_token from the response. You'll need it for the next steps.

Step 2: Decode the Token

JWTs are base64-encoded. Let's see what's inside. Copy your token and paste it at jwt.io, or use this PowerShell command:

PowerShell - Decode JWT
# Replace YOUR_TOKEN with the access_token you received $token = "YOUR_TOKEN" # Split the token and decode the payload (middle part) $parts = $token.Split('.') $payload = $parts[1] # Add padding if needed and decode $padding = 4 - ($payload.Length % 4) if ($padding -lt 4) { $payload += "=" * $padding } [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($payload)) | ConvertFrom-Json | ConvertTo-Json # You should see claims like: sub, aud, scope, iss, exp, iat
βœ…
Self-Check Questions

Looking at your decoded token:

  • What is the iss (issuer)? Does it match the IdP URL?
  • What scopes were granted in the scope claim?
  • When does the token expire? (Check exp - it's a Unix timestamp)
  • What is the sub (subject)? This identifies who the token represents.

Step 3: Use the Token for Authorization

Now let's check if this token's subject has permission to do something. We'll ask the PDP if "alice" can read a document:

πŸ§ͺ Check Authorization with PDP

This is an AuthZEN evaluation request. The response will be PERMIT or DENY:

Try modifying the request: change the action to "delete" or the resource type to "admin-panel". Does the decision change? Understanding these patterns is key to working with the PDP.

Lab 3: The Log Investigation Challenge (10 minutes)

This lab simulates a real debugging scenario. You'll generate traffic, find it in the logs, and trace a request through the system.

Step 1: Set Up Your Terminals

Open two terminal windows:

Step 2: Start Watching Logs

In Terminal 1, start following the BFF logs:

Terminal 1 - Log Watcher
# Watch BFF logs in real-time docker compose logs -f bff # You'll see logs streaming as requests come in # Look for entries with "correlation_id" - that's your tracking number

Step 3: Generate Traffic

In Terminal 2, make a request and note the correlation ID:

Terminal 2 - Generate Request
# Make a health check request (returns headers including correlation ID) curl -v https://bff.self.empowernow.ai/health 2>&1 | Select-String "correlation|x-request" # Or use PowerShell to capture headers $response = Invoke-WebRequest -Uri "https://bff.self.empowernow.ai/health" -Headers @{Accept="application/json"} $response.Headers # Note the X-Correlation-ID value (something like "abc123-def456-...")

Step 4: Find Your Request in the Logs

Now use the correlation ID to find your specific request in the logs:

Terminal 2 - Find Your Request
# Replace YOUR_CORRELATION_ID with the actual value docker compose logs --tail 500 | Select-String "YOUR_CORRELATION_ID" # You should see multiple log entries - one for request start, one for completion # If your request touched IdP or PDP, you'd see it there too
βœ…
Challenge: Find an Error

Now intentionally cause an error and find it in the logs:

  1. Make a request to a non-existent endpoint: curl https://bff.self.empowernow.ai/does-not-exist
  2. Find the 404 in the logs using: docker compose logs bff | Select-String "404"
  3. Can you find the correlation ID for the failed request?

Lab 4: The Container Deep Dive (5 minutes)

Sometimes logs aren't enough. Let's go inside a container and explore.

Step 1: Enter the Container

PowerShell
# Get a shell inside the BFF container docker exec -it bff_app /bin/sh # You're now INSIDE the container. The prompt changes to show you're in a different environment.

Step 2: Explore the Environment

Inside the container, run these commands and observe the output:

Inside Container
# Where is the application code? ls -la /app # What secrets are mounted? ls -la /run/secrets/ # What environment variables are set? (Look for IdP, Redis URLs) printenv | grep -i "idp\|redis\|bff" | sort # Can we reach the IdP from here? wget -qO- http://idp-app:8002/health # Check network resolution cat /etc/hosts cat /etc/resolv.conf # Exit the container when done exit
βœ…
Self-Check

After exploring, can you answer:

  • What's the BFF's internal Redis URL?
  • How many secret files are mounted?
  • What Python version is running? (hint: python --version)
  • Can you curl the PDP from inside the BFF container?

Lab 5: Build Your Own Health Dashboard (Bonus - 5 minutes)

Let's create a simple script that checks all services at once β€” a tool you'll use regularly.

health-check.ps1
# Save this as health-check.ps1 in your Deployment folder $services = @{ "BFF" = "https://bff.self.empowernow.ai/health" "IdP" = "https://idp.self.empowernow.ai/health" "PDP" = "https://pdp.self.empowernow.ai/health" "Membership" = "https://membership.self.empowernow.ai/health" } Write-Host "`n===== EmpowerNow Health Check =====" -ForegroundColor Cyan Write-Host "Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`n" foreach ($service in $services.GetEnumerator()) { try { $response = Invoke-WebRequest -Uri $service.Value -TimeoutSec 5 -ErrorAction Stop $status = ($response.Content | ConvertFrom-Json).status if ($status -eq "healthy") { Write-Host "βœ… $($service.Key)" -ForegroundColor Green -NoNewline Write-Host " - healthy" -ForegroundColor DarkGray } else { Write-Host "⚠️ $($service.Key)" -ForegroundColor Yellow -NoNewline Write-Host " - $status" -ForegroundColor DarkGray } } catch { Write-Host "❌ $($service.Key)" -ForegroundColor Red -NoNewline Write-Host " - FAILED: $($_.Exception.Message)" -ForegroundColor DarkGray } } Write-Host "`n===================================`n"

Save the script and run it:

PowerShell
# Run the health check .\health-check.ps1 # Run it in a loop every 10 seconds (Ctrl+C to stop) while ($true) { .\health-check.ps1; Start-Sleep 10 }
πŸŽ‰
Lab Complete!

You've now explored services, decoded tokens, traced logs, inspected containers, and built a monitoring tool. These are the core skills you'll use every day when working with EmpowerNow.

πŸ“Š Your First Metrics Journey

Numbers tell stories. Every request, every error, every millisecond of latency is recorded. Let's learn to read these stories and understand what your services are really doing.

EmpowerNow services expose metrics in Prometheus format. These metrics are scraped by Prometheus and visualized in Grafana. Here's how the data flows:

The Metrics Pipeline
flowchart LR subgraph services [Services] BFF[BFF :8000/metrics] IdP[IdP :8002/metrics] PDP[PDP :8001/metrics] end subgraph collection [Collection] Prom[(Prometheus)] end subgraph viz [Visualization] Graf[Grafana Dashboards] end BFF --> Prom IdP --> Prom PDP --> Prom Prom --> Graf

What Metrics Tell You

Metrics answer questions you didn't know you had:

πŸ§ͺ Try It: See Raw Metrics

This is what Prometheus scrapes every 15 seconds. Look for http_requests_total and http_request_duration_seconds:

Your First Prometheus Query

Once you're in Prometheus (at prometheus.self.empowernow.ai), try these queries to understand what's happening:

PromQL Queries
# How many requests in the last 5 minutes? increase(http_requests_total[5m]) # Request rate per second rate(http_requests_total[5m]) # Only error responses (5xx status codes) rate(http_requests_total{status=~"5.."}[5m]) # 95th percentile response time histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

Navigating Grafana

Grafana turns these raw numbers into beautiful, actionable dashboards. Here's your quick-start guide:

  1. First login: Navigate to grafana.self.empowernow.ai, login with admin / admin
  2. Find dashboards: Click the hamburger menu β†’ Dashboards β†’ Browse
  3. Look for: "BFF Overview", "IdP Metrics", "PDP Performance"
  4. Time range: Use the time picker (top-right) to zoom in on incidents
πŸ’œ
The Golden Signals

When looking at dashboards, focus on: Latency (how fast), Traffic (how much), Errors (how often things fail), and Saturation (how full your resources are). These four tell you almost everything you need to know.

🐳 Inside the Container

Sometimes you need to go inside to understand what's happening. Let's explore the container filesystem like archaeologists examining an ancient temple.

Containers are isolated environments, but you can shell into them to poke around. This is invaluable when logs aren't telling the whole story.

Inside a Typical Service Container
flowchart TB subgraph container [BFF Container] app["/app
Application Code"] secrets["/run/secrets
Mounted Secrets"] logs["/logs
Log Files"] tmp["/tmp
Temp Files"] end subgraph host [Host Machine] configsecrets["config_secrets/"] envfiles["env/services/bff.env"] end configsecrets -.->|"mounted as files"| secrets envfiles -.->|"loaded as env vars"| app

Getting a Shell

Shell Access
# Get an interactive shell in BFF docker exec -it bff_app /bin/sh # Once inside, explore: ls -la /app # Application code ls -la /run/secrets # Mounted secrets (filenames only!) printenv | grep -i idp # Environment variables cat /etc/hosts # Container's hosts file

Network Debugging from Inside

Containers have their own network namespace. Sometimes the issue is that one container can't reach another. Here's how to test:

Network Tests
# From BFF, can we reach IdP? docker exec bff_app wget -qO- http://idp-app:8002/health # Can we reach the database? docker exec bff_app nc -zv postgres 5432 # What DNS names are available? docker exec bff_app cat /etc/resolv.conf # List all containers on the network docker network inspect empowernow_default | jq '.[0].Containers'

Resource Inspection

Is a container eating all your memory? Is CPU maxed out? Here's how to check:

Resource Commands
# Live resource usage (like top for containers) docker stats --no-stream # Detailed container state docker inspect bff_app | jq '.[0].State' # Check if container is resource-limited docker inspect bff_app | jq '.[0].HostConfig.Memory' # View container's process list docker exec bff_app ps aux
πŸ§ͺ Exploration Exercise: Find the Secrets

Try this sequence to explore inside a container:

  1. Shell into BFF: docker exec -it bff_app /bin/sh
  2. List the secrets directory: ls -la /run/secrets/
  3. Check an environment variable: echo $BFF_COOKIE_DOMAIN
  4. Test network to IdP: wget -qO- http://idp-app:8002/health
  5. Exit the container: exit

πŸš€ Advanced Topics

Data Collector (DC UI)

The Data Collector is a key component for inventory collection and data integration. Its UI is delivered as an Experience platform plugin (experience/plugins/dc-ui/), accessible alongside IT Shop, My Identity, and other modules. Day 26 covers DataCollector concepts; day 27 covers the DC-UI in depth.

πŸ“Š
What is Data Collector?

The Data Collector service discovers and inventories systems, users, and resources across your enterprise. It connects to various sources (AD, databases, cloud services) to build a comprehensive view of your environment.

Starting the Data Collector Profile

PowerShell
# Start Data Collector with core services docker compose --profile core --profile datacollector up -d # View Data Collector services docker compose ps | Select-String "datacollector|dc-"

Data Collector Services

πŸ”
datacollector
Port: 8085

Core data collection engine - connects to external systems

πŸ–₯️
dc-ui
datacollector.self.empowernow.ai

Administrative UI for configuring collection jobs and viewing inventory

πŸ“¦
dc-alembic
Migrations

Database migrations for Data Collector schema

πŸ”Œ
DC-UI is an Experience platform plugin

The Data Collector UI is loaded as a plugin under the Experience platform β€” typically reachable at /dc-ui/ through the Experience shell. Day 16 walks through the basics; days 27–28 are the full reference.

Your App Needs an Identity: Client Registration

Every application that talks to EmpowerNow needs an identity β€” a client ID and credentials. Think of it like getting a passport. Without one, your app can't authenticate, can't get tokens, can't do anything. Let's walk through the registration process.

Dynamic Client Registration (DCR) lets you create OAuth clients programmatically. This is how CI/CD pipelines, AI agents, and new services get their credentials automatically, without someone manually clicking through an admin UI.

The Client Lifecycle

A client goes through several stages from creation to retirement:

OAuth Client Lifecycle
stateDiagram-v2 [*] --> Unregistered Unregistered --> Registered: POST /register Registered --> Active: First token request Active --> Active: Normal operations Active --> SecretRotated: Rotate credentials SecretRotated --> Active: Use new secret Active --> Revoked: DELETE /register Revoked --> [*]

Client Profiles

Not all clients are created equal. Choose the right profile for your use case:

🌐
Public Client
For browser-based SPAs and mobile apps that can't securely store secrets. Uses PKCE for security instead of a client secret.
No secret, PKCE required
πŸ”’
Confidential Client
For backend services that can securely store a client secret. The most common type for microservices and BFFs.
Secret required
πŸ€–
Agent Client
For AI agents that need to authenticate and carry capabilities. Includes metadata about agent class and permissions.
JWT assertion, agent metadata
βš™οΈ
Service Client
For machine-to-machine communication using client credentials grant. No user interaction, just service-to-service auth.
client_credentials only

Step-by-Step: Register Your First Client

Let's walk through registering a confidential client for a backend service:

πŸ§ͺ Step 1: Register the Client

This creates a new OAuth client. Save the client_id and client_secret from the response!

πŸ§ͺ Step 2: Get a Token with Your Client

Now use your new client credentials to get an access token. Replace the Authorization header with your actual credentials (base64 encoded client_id:client_secret):

Managing Your Clients

Once registered, you can manage your clients via the same endpoint:

Client Management
# View your client configuration curl https://idp.../api/oidc/register/YOUR_CLIENT_ID \ -H "Authorization: Bearer YOUR_REGISTRATION_TOKEN" # Update client settings curl -X PUT https://idp.../api/oidc/register/YOUR_CLIENT_ID \ -H "Authorization: Bearer YOUR_REGISTRATION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"client_name": "Updated Name"}' # Delete the client (revoke all tokens) curl -X DELETE https://idp.../api/oidc/register/YOUR_CLIENT_ID \ -H "Authorization: Bearer YOUR_REGISTRATION_TOKEN"
πŸ“š
Want to Go Deeper?

For advanced DCR behavior, secret handling, and compliance-oriented detail, use the official EmpowerNow documentation and your support channel rather than internal deep-dive bundles.

Quick Reference: Client Types

Client Type Use Case Secret Required Example
public SPAs, mobile apps ❌ No React/Angular frontend
confidential Backend services βœ… Yes BFF, microservices

Agent Registration (A2A)

AI agents use a special client profile for registration:

JSON
# Agent-specific DCR request POST /api/oidc/register { "client_profile": "agent-app", "client_name": "Invoice Processing Agent", "jwks_uri": "https://agent.empowerid.com/.well-known/jwks.json", "custom_metadata": { "agent": { "class": "llm-assistant", "capabilities": ["invoice:read", "invoice:approve"] } } } # Agent ARN format: auth:agent:{tenant}:{client_id} # Example: auth:agent:acme-corp:invoice-agent
πŸ€–
Preview: Agent Lifecycle v2.0

In Week 5, Day 23, you'll learn about vault-backed agent credentials where secrets are never exposed in plaintext. The Bootstrap API uses Initial Access Tokens (IATs), stores credentials in Vault, and supports multi-IdP registration (Auth0, Entra ID, Salesforce).

OAuth Clients Database Schema

Understanding how clients are stored helps with debugging:

SQL
-- Core table (hot path - token endpoint reads this) CREATE TABLE idp.oauth_clients ( client_id TEXT PRIMARY KEY, client_name TEXT NOT NULL, client_type TEXT CHECK (client_type IN ('public', 'confidential')), secret_hash TEXT, redirect_uris TEXT[] DEFAULT '{}', grant_types TEXT[] DEFAULT '{authorization_code}', scopes TEXT[] DEFAULT '{openid}', fapi_profile TEXT DEFAULT 'none', token_endpoint_auth TEXT DEFAULT 'client_secret_basic' ); -- Extension table (config, metadata - not on hot path) CREATE TABLE idp.oauth_client_ext ( client_id TEXT PRIMARY KEY REFERENCES idp.oauth_clients, config JSONB DEFAULT '{}', -- TTLs, feature flags metadata JSONB DEFAULT '{}' -- UI prefs, contact info );
⚠️
BFF Registration Script

The BFF service needs to be registered with IdP on first startup. If BFF is failing to authenticate, run the script from ServiceConfigs/Deployment to create the admin JWT secret used for BFF Dynamic Client Registration (DCR):

# Windows (PowerShell):
.\scripts\create-idp-admin-jwt-secret.ps1

# Mac/Linux:
./scripts/create-idp-admin-jwt-secret.sh

πŸ“ Knowledge Check

Before moving on to Week 2, let's make sure you've absorbed the key concepts. Try to answer these questions without looking back. If you get stuck, revisit the relevant section.

Service Architecture

❓
Question 1: The BFF's Role

What does the BFF (Backend-for-Frontend) do? Why do browsers talk to the BFF instead of directly to IdP or PDP?

Show Answer

The BFF acts as a gateway and authentication proxy. Browsers can't securely store client secrets, so the BFF handles OAuth flows, stores sessions in Redis, and proxies API requests. It also handles CSRF protection and adds security headers.

❓
Question 2: Request Flow

When a user clicks "Login," what's the sequence of services involved? (Hint: Think about the flow diagram)

Show Answer

Browser β†’ BFF (initiates OAuth) β†’ IdP (authentication) β†’ BFF (receives code, exchanges for tokens) β†’ Redis (stores session) β†’ PDP (checks permissions) β†’ BFF β†’ Browser (welcome message)

Debugging Skills

❓
Question 3: The Correlation ID

What is a correlation ID and why is it important for debugging?

Show Answer

A correlation ID is a unique identifier assigned to a request when it enters the system. It's passed through every service the request touches, appearing in all related log entries. This lets you trace a single request's journey through multiple services and find exactly where something went wrong.

❓
Question 4: Container in Restart Loop

The BFF container keeps restarting. What are the first two things you should check?

Show Answer

1. Check the logs: docker compose logs bff --tail 50 β€” look for error messages about missing secrets or configuration.

2. Check if secrets exist: ls config_secrets/ β€” the BFF needs certain secrets to start. Run the initialization scripts if they're missing.

Authentication & Authorization

❓
Question 5: JWT Structure

A JWT has three parts. What are they and what does each contain?

Show Answer

1. Header - Contains the algorithm (e.g., RS256) and token type (JWT)
2. Payload - Contains claims: sub (subject), iss (issuer), exp (expiration), scope, etc.
3. Signature - Cryptographic signature to verify the token wasn't tampered with

❓
Question 6: IdP vs PDP

What's the difference between what IdP does and what PDP does?

Show Answer

IdP (Identity Provider) handles authentication β€” "Who are you?" It verifies credentials and issues tokens.

PDP (Policy Decision Point) handles authorization β€” "What can you do?" It evaluates policies and returns PERMIT/DENY decisions.

Practical Commands

❓
Question 7: Essential Commands

Without looking, write the commands to:

  • Check which containers are running
  • View the last 100 lines of IdP logs
  • Get a shell inside the BFF container
Show Answer

docker compose ps

docker compose logs --tail 100 idp

docker exec -it bff_app /bin/sh

πŸ†
How Did You Do?

6-7 correct without hints: Excellent! You're ready for Week 2.
4-5 correct: Good foundation. Review the sections you struggled with.
Less than 4: Consider re-reading Day 5 and re-doing the labs before moving on.

πŸŽ‰ Week 1 Complete!

Week 1 Recap: Foundations & Environment

Day 01
Platform Architecture
Day 02
Environment Setup
Day 03
Docker Profiles
Day 04
Configuration & Secrets
Day 05
Exploring Services
πŸŽ‰
Congratulations!

You've completed Week 1! You now have a solid foundation in the EmpowerNow platform architecture, development environment, and operational knowledge.

What You Learned This Week:

Next Week Preview: Core Services Deep Dive

In Week 2, you'll dive deep into the authentication and authorization services: