P3.9: End-to-end integration test — user login through token exchange to downstream #13

Closed
opened 2026-09-08 03:57:53 +00:00 by rock · 0 comments
Owner

Summary

Document and script the complete auth flow end-to-end. Serves as both integration test and usage documentation.

Test scenarios

Scenario 1: User direct call

# 1. User gets token with password
TOKEN=$(curl -s POST https://api.riotpiao.com/auth/token \
  -d '{"username":"rock","password":"..."}' | jq -r .access_token)

# 2. Decode and verify claims
echo $TOKEN | cut -d. -f2 | base64 -d | jq .
# Expect: sub=rock, permissions=["*"]

# 3. Call LLM API
curl https://api.riotpiao.com/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"model":"reasoning","messages":[{"role":"user","content":"say ok"}]}'
# Expect: 200, streaming response

# 4. Verify downstream saw identity headers
kubectl logs -n llm-serving deploy/reasoning-predictor | grep X-Forwarded-User
# (vLLM doesn't log headers, but memory service will)

Scenario 2: Service-to-service (own identity)

SA_TOKEN=$(curl -s POST https://authentik.riotpiao.com/application/o/token/ \
  -d "grant_type=client_credentials&client_id=portfolio-agent&client_secret=$SECRET&scope=openid roles")

curl https://api.riotpiao.com/v1/chat/completions \
  -H "Authorization: Bearer $(echo $SA_TOKEN | jq -r .access_token)" \
  -d '{"model":"reasoning","messages":[...]}'
# Expect: 200, X-Forwarded-User=portfolio-agent, X-Acting-Service absent

Scenario 3: Token exchange (delegated identity)

# portfolio-agent exchanges rock's token for memory-scoped token
EXCHANGED=$(curl -s POST https://api.riotpiao.com/auth/exchange \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
  -d "subject_token=$USER_TOKEN" \
  -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
  -d "client_id=portfolio-agent&client_secret=$SECRET" \
  -d "scope=memory:read&resource=poimen-memory")

# Call memory service with exchanged token
curl -H "X-Service: memory" -H "X-Resource: query" \
  -H "Authorization: Bearer $(echo $EXCHANGED | jq -r .access_token)" \
  https://api.riotpiao.com/ -d '{"query":"..."}'
# Expect: X-Forwarded-User=rock, X-Acting-Service=portfolio-agent

Scenario 4: Error cases

  • Wrong password returns 401
  • Expired token returns 403
  • Missing capability returns 403 with "Insufficient Permissions"
  • Token exchange scope escalation rejected
  • Spoofed X-Forwarded-User header stripped

Acceptance Criteria

  • All scenarios documented in docs/auth-flows.md
  • Shell script in scripts/test-auth-e2e.sh (interactive, prompts for password)
  • Each scenario has expected output and failure modes
  • Ran successfully against live cluster at least once
## Summary Document and script the complete auth flow end-to-end. Serves as both integration test and usage documentation. ## Test scenarios ### Scenario 1: User direct call ```bash # 1. User gets token with password TOKEN=$(curl -s POST https://api.riotpiao.com/auth/token \ -d '{"username":"rock","password":"..."}' | jq -r .access_token) # 2. Decode and verify claims echo $TOKEN | cut -d. -f2 | base64 -d | jq . # Expect: sub=rock, permissions=["*"] # 3. Call LLM API curl https://api.riotpiao.com/v1/chat/completions \ -H "Authorization: Bearer $TOKEN" \ -d '{"model":"reasoning","messages":[{"role":"user","content":"say ok"}]}' # Expect: 200, streaming response # 4. Verify downstream saw identity headers kubectl logs -n llm-serving deploy/reasoning-predictor | grep X-Forwarded-User # (vLLM doesn't log headers, but memory service will) ``` ### Scenario 2: Service-to-service (own identity) ```bash SA_TOKEN=$(curl -s POST https://authentik.riotpiao.com/application/o/token/ \ -d "grant_type=client_credentials&client_id=portfolio-agent&client_secret=$SECRET&scope=openid roles") curl https://api.riotpiao.com/v1/chat/completions \ -H "Authorization: Bearer $(echo $SA_TOKEN | jq -r .access_token)" \ -d '{"model":"reasoning","messages":[...]}' # Expect: 200, X-Forwarded-User=portfolio-agent, X-Acting-Service absent ``` ### Scenario 3: Token exchange (delegated identity) ```bash # portfolio-agent exchanges rock's token for memory-scoped token EXCHANGED=$(curl -s POST https://api.riotpiao.com/auth/exchange \ -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ -d "subject_token=$USER_TOKEN" \ -d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \ -d "client_id=portfolio-agent&client_secret=$SECRET" \ -d "scope=memory:read&resource=poimen-memory") # Call memory service with exchanged token curl -H "X-Service: memory" -H "X-Resource: query" \ -H "Authorization: Bearer $(echo $EXCHANGED | jq -r .access_token)" \ https://api.riotpiao.com/ -d '{"query":"..."}' # Expect: X-Forwarded-User=rock, X-Acting-Service=portfolio-agent ``` ### Scenario 4: Error cases - Wrong password returns 401 - Expired token returns 403 - Missing capability returns 403 with "Insufficient Permissions" - Token exchange scope escalation rejected - Spoofed X-Forwarded-User header stripped ## Acceptance Criteria - [ ] All scenarios documented in `docs/auth-flows.md` - [ ] Shell script in `scripts/test-auth-e2e.sh` (interactive, prompts for password) - [ ] Each scenario has expected output and failure modes - [ ] Ran successfully against live cluster at least once
rock added this to the Phase 3: OAuth2 Token Exchange & Identity Propagation milestone 2026-09-08 03:57:53 +00:00
rock added the type/docsarea/autharea/gatewaypriority/mediumstatus/todo labels 2026-09-08 03:57:53 +00:00
rock self-assigned this 2026-09-08 03:57:53 +00:00
rock added this to the (deleted) project 2026-09-08 04:37:14 +00:00
rock closed this issue 2026-09-08 04:45:26 +00:00
Sign in to join this conversation.