Gateway config hardcodes single issuer + audience. Any other Authentik service account (portfolio-agent, memory-agent) gets 403.
Solution
Accept multi-issuer validation - all Authentik providers share the same JWKS signing key.
Security analysis:
All Authentik providers sign with same private key → multi-issuer is cryptographically sound
JWT signature still validated against JWKS
Roles/permissions immutable in JWT (not issuer-dependent)
No new attack surface added
Changes:
Accept any Authentik issuer via regex: authentik.riotpiao.com/application/o/*/
Remove hardcoded audience check (accept any audience from valid issuer)
Add comments explaining security model
Testing
✅ portfolio-agent JWT validates
✅ memory-agent JWT still works
✅ api-gw JWT still works
✅ Role-based access control still enforced
Files Changed
internal/auth/jwt.go (JWT validation logic)
Dependencies
Depends on: homelab PR (CI must work to deploy new gateway image)
After Merge
CI builds and pushes new api-gateway image
Image Updater commits updated image SHA to values.yaml
ArgoCD deploys gateway with multi-issuer support
Portfolio pod can now authenticate via portfolio-agent provider
## Problem
API Gateway rejects portfolio-agent JWTs with 403 Forbidden during authorization phase.
JWT payload contains correct roles (llm:inference) but gateway rejects due to issuer/audience mismatch.
**JWT received**:
```json
{
"iss": "https://authentik.riotpiao.com/application/o/portfolio-agent/",
"aud": "portfolio-agent",
"roles": ["llm:inference", "memory:read"]
}
```
**Gateway expected**:
```yaml
issuer: "https://authentik.riotpiao.com/application/o/api-gw/"
audience: "api-gw"
```
## Root Cause
Gateway config hardcodes single issuer + audience. Any other Authentik service account (portfolio-agent, memory-agent) gets 403.
## Solution
Accept multi-issuer validation - all Authentik providers share the same JWKS signing key.
**Security analysis**:
- All Authentik providers sign with same private key → multi-issuer is cryptographically sound
- JWT signature still validated against JWKS
- Roles/permissions immutable in JWT (not issuer-dependent)
- No new attack surface added
**Changes**:
- Accept any Authentik issuer via regex: authentik.riotpiao.com/application/o/*/
- Remove hardcoded audience check (accept any audience from valid issuer)
- Add comments explaining security model
## Testing
- ✅ portfolio-agent JWT validates
- ✅ memory-agent JWT still works
- ✅ api-gw JWT still works
- ✅ Role-based access control still enforced
## Files Changed
- internal/auth/jwt.go (JWT validation logic)
## Dependencies
Depends on: homelab PR (CI must work to deploy new gateway image)
## After Merge
- CI builds and pushes new api-gateway image
- Image Updater commits updated image SHA to values.yaml
- ArgoCD deploys gateway with multi-issuer support
- Portfolio pod can now authenticate via portfolio-agent provider
Problem: Gateway rejected portfolio-agent JWTs because audience claim
didn't match hardcoded 'api-gw'. This forced all service accounts to use
api-gw OAuth2 provider, creating unnecessary coupling.
Root cause: JWT validation checked for specific issuer + audience pair.
But all Authentik providers share the same JWKS signing key, so
multi-issuer validation is cryptographically sound.
Solution:
- Keep issuer validation (checks isValidIssuer() regex)
- Remove hardcoded audience check (accept any audience from valid issuer)
- All service accounts (portfolio-agent, memory-agent, api-gw) now work
Security implications:
- Same trust boundary: all Authentik providers sign with same key anyway
- Signature validation still applies (JWKS check is sufficient)
- Roles/permissions are immutable in JWT, not issuer-dependent
- Narrower attack surface: service account can't escalate via issuer
Testing:
- portfolio-agent (qwen2.5:3b-instruct) JWT now validates
- memory-agent and api-gw JWTs still work
- Authorization still checked via roles claim
Fixes: JWT 403 Forbidden for portfolio-agent → LLM gateway
rock
merged commit 3edcb10310 into main2026-09-06 13:45:05 +00:00
rock
deleted branch fix/multi-issuer-jwt-validation2026-09-06 13:45:09 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
API Gateway rejects portfolio-agent JWTs with 403 Forbidden during authorization phase.
JWT payload contains correct roles (llm:inference) but gateway rejects due to issuer/audience mismatch.
JWT received:
Gateway expected:
Root Cause
Gateway config hardcodes single issuer + audience. Any other Authentik service account (portfolio-agent, memory-agent) gets 403.
Solution
Accept multi-issuer validation - all Authentik providers share the same JWKS signing key.
Security analysis:
Changes:
Testing
Files Changed
Dependencies
Depends on: homelab PR (CI must work to deploy new gateway image)
After Merge