Commit 4c8a912
feat(auth): add upstream header auth provider for gateway deployments (#5563)
# What does this PR do?
Adds a new `upstream_header` authentication provider that extracts user
identity from headers injected by an upstream gateway (Authorino, Istio,
or any reverse proxy that handles auth). This enables Llama Stack to
participate in gateway-fronted deployments without redundant token
validation, while still scoping all storage queries to the authenticated
user via the existing `AuthorizedSqlStore` pipeline.
The `AuthProvider` base class gains a `requires_http_bearer` property
(default `True`) so the `AuthenticationMiddleware` can skip Bearer token
extraction for providers that read identity from other sources. The
`authenticated_client_id` falls back to the principal when no token is
present, preserving quota tracking.
Configuration:
```yaml
server:
auth:
provider_config:
type: upstream_header
principal_header: x-auth-user-id # required
attributes_header: x-auth-attributes # optional, JSON dict
```
## Test Plan
17 unit tests covering provider behavior and middleware integration:
```bash
uv run pytest tests/unit/server/test_auth_upstream_header.py -v
```
```
tests/unit/server/test_auth_upstream_header.py::test_valid_upstream_header_auth PASSED
tests/unit/server/test_auth_upstream_header.py::test_valid_upstream_header_auth_principal_only PASSED
tests/unit/server/test_auth_upstream_header.py::test_missing_principal_header PASSED
tests/unit/server/test_auth_upstream_header.py::test_invalid_attributes_json PASSED
tests/unit/server/test_auth_upstream_header.py::test_attributes_not_object PASSED
tests/unit/server/test_auth_upstream_header.py::test_no_bearer_token_required PASSED
tests/unit/server/test_auth_upstream_header.py::test_bearer_token_ignored PASSED
tests/unit/server/test_auth_upstream_header.py::test_no_attributes_header_configured PASSED
tests/unit/server/test_auth_upstream_header.py::test_case_insensitive_headers PASSED
tests/unit/server/test_auth_upstream_header.py::test_attributes_string_values_normalized PASSED
tests/unit/server/test_auth_upstream_header.py::test_error_message_includes_header_name PASSED
tests/unit/server/test_auth_upstream_header.py::test_authenticated_client_id_uses_principal PASSED
tests/unit/server/test_auth_upstream_header.py::test_provider_requires_http_bearer_false PASSED
tests/unit/server/test_auth_upstream_header.py::test_provider_validate_token_extracts_principal PASSED
tests/unit/server/test_auth_upstream_header.py::test_provider_validate_token_extracts_attributes PASSED
tests/unit/server/test_auth_upstream_header.py::test_provider_validate_token_missing_principal PASSED
tests/unit/server/test_auth_upstream_header.py::test_provider_validate_token_none_scope PASSED
```
All 35 existing auth tests continue to pass.
Signed-off-by: Sébastien Han <seb@redhat.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent 043394d commit 4c8a912
4 files changed
Lines changed: 394 additions & 10 deletions
File tree
- src/llama_stack/core
- server
- tests/unit/server
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
213 | 213 | | |
214 | 214 | | |
215 | 215 | | |
| 216 | + | |
216 | 217 | | |
217 | 218 | | |
218 | 219 | | |
| |||
320 | 321 | | |
321 | 322 | | |
322 | 323 | | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
323 | 342 | | |
324 | | - | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
325 | 348 | | |
326 | 349 | | |
327 | 350 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
120 | 120 | | |
121 | 121 | | |
122 | 122 | | |
123 | | - | |
124 | | - | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
125 | 126 | | |
126 | | - | |
127 | | - | |
128 | | - | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
129 | 130 | | |
130 | | - | |
131 | | - | |
| 131 | + | |
| 132 | + | |
132 | 133 | | |
133 | | - | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
134 | 137 | | |
135 | 138 | | |
136 | 139 | | |
| |||
147 | 150 | | |
148 | 151 | | |
149 | 152 | | |
150 | | - | |
| 153 | + | |
151 | 154 | | |
152 | 155 | | |
153 | 156 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| |||
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
63 | 73 | | |
64 | 74 | | |
65 | 75 | | |
| |||
502 | 512 | | |
503 | 513 | | |
504 | 514 | | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
505 | 579 | | |
506 | 580 | | |
507 | 581 | | |
| |||
514 | 588 | | |
515 | 589 | | |
516 | 590 | | |
| 591 | + | |
| 592 | + | |
517 | 593 | | |
518 | 594 | | |
0 commit comments