feat(core): add scoped impersonation tokens - #129
Conversation
BK1031
commented
Sep 9, 2026
- Add a service-account-only endpoint for issuing user impersonation tokens to a target application
- Issue five-minute JWTs with authoritative user/group claims and an RFC 8693 actor claim
- Use sentinel:all for the Sentinel application and user:read groups:read for other applications
- Enforce application group gates and restrict sentinel:impersonate grants to privileged service-account creators
- Persist the actor on token records and audit every impersonation issuance
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b142859af
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if RequestTokenHasScope(c, "sentinel:all") || RequestUserIsAdmin(c) { | ||
| validateScope = service.ValidatePrivilegedServiceAccountScope |
There was a problem hiding this comment.
Recheck privileged scope authorization during rotation
When an admin creates a service account carrying sentinel:impersonate for an application owned by somebody else, that application's non-admin owner can call the existing rotate endpoint, which reuses the stored scope and returns the new raw token. This bypasses the new creation-time restriction and gives an unprivileged owner an impersonation credential; rotation must apply the privileged-scope authorization as well.
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| func impersonationGroups(entityID string, application model.Application) ([]model.Group, error) { | ||
| userGroups, err := GetGroupsForEntity(entityID) |
There was a problem hiding this comment.
Exclude expired memberships from impersonation groups
GetGroupsForEntity returns every group_member row without checking has_expiration or expires_at, so a user whose required membership has expired still passes passesApplicationGate, and the expired group is embedded in the impersonation token. Load only active memberships here before enforcing the application gate and constructing authoritative group claims.
Useful? React with 👍 / 👎.