[console] OIDC header shows "User" because getPrincipalNameFromToken always uses JWT `sub`
- Dominant language
- TypeScript
- Stars
- 33
- Forks
- 46
- Avg merge
- 1d 4m
- Merged PRs (30d)
- 2
Description
## Description
After a successful OIDC login (Microsoft Entra ID), the Console header shows **User** and avatar initials **US**, even though:
1. Polaris Server maps the principal by `preferred_username` (email / UPN).
2. The access token contains `name` and `preferred_username`.
3. `GET /api/management/v1/principals` returns that principal (e.g. `user@example.com`).
4. Catalogs and other management APIs work as that principal.
The Console then calls `GET /api/management/v1/principals/{sub}` and gets **404**. A follow-up `principal-roles` call also fails. The header falls back to `"User"`.
This looks Keycloak-centric: OIDC was added in #168 / #125 and tested with Keycloak, where `sub` is often the same as the Polaris principal name. Entra (and many other IdPs) use an opaque pairwise `sub` that is **not** the principal name.
## Root cause
[`console/src/lib/utils.ts`](https://github.com/apache/polaris-tools/blob/main/console/src/lib/utils.ts) — `getPrincipalNameFromToken()`:
```ts
return (
(decoded.sub as string) ||
(decoded.principal as string) ||
(decoded.principal_name as string) ||
(decoded.name as string) ||
null
)
```
## Actual
| Item | Result |
|------|--------|
| OIDC login | Succeeds |
| Header | User / initials US |
| `GET /api/management/v1/principals` | 200 — includes `user@example.com` (and `root`) |
| `GET /api/management/v1/principals/{entra-sub}` | 404 |
| `GET .../principals/{entra-sub}/principal-roles` | fails as a follow-on |
| Client-credentials login as `root` | Header correctly shows `root` |
Token claims present (redacted): `name` = display name, `preferred_username` = email/UPN, `sub` = opaque id, `scp` includes the Polaris API scope.
## Steps to reproduce
1. Configure Polaris Server mixed auth with an IdP where `sub` ≠ principal name, e.g.:
- `polaris.oidc.principal-mapper.name-claim-path=preferred_username`
- do **not** set `id-claim-path`
2. Create a Polaris principal named after `preferred_username` (email/UPN) and grant a principal role.
3. Configure Console OIDC (`VITE_OIDC_*`) against that IdP (Entra ID v2, or any IdP with opaque `sub`).
4. Log in via **Login with OIDC**.
5. In DevTools → Network, observe `GET /api/management/v1/principals/{sub}` → 404.
6. Header still shows **User**.
## Suggested fix
1. Change claim precedence in `getPrincipalNameFromToken` so opaque `sub` is last, e.g. `preferred_username` → `principal_name` → `principal` → `name` → `email` → `sub`.
2. Better: make the claim configurable (`VITE_OIDC_PRINCIPAL_CLAIM` / `config.oidc.principalClaim`) so Console can match server `name-claim-path`.
3. If `GET /principals/{id}` 404s, fall back to JWT `name` / `preferred_username` for the header instead of hardcoded `"User"`.
4. Optionally resolve the current user from the principals list by matching `preferred_username`.
## Environment
- Component: Polaris Console (`apache/polaris-tools` `console/`)
- Branch: `main` (`getPrincipalNameFromToken` as above)
- IdP: Microsoft Entra ID (OIDC v2, PKCE public client)
- Polaris Server: mixed internal + OIDC; principal mapped by `preferred_username`
- Related: #125 (OIDC, closed), #168 (OIDC PR, Keycloak), #176 (OIDC improvements — different scope)
- Server-side mapping discussion (not this UI bug): apache/polaris#2373, apache/polaris#3059
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in `console/src/lib/utils.ts` and read `getPrincipalNameFromToken()`, then trace how its result is used to fetch the current principal and populate the header. The issue describes the failure when an IdP's opaque `sub` differs from the Polaris principal name, and suggests several possible fixes. Done should mean the header identifies the mapped principal rather than falling back to “User” for this OIDC case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100