Feature #44430
openFine-grained Personal Access Tokens
Description
Extracted from #43881 only the part that implements the fine grained personal access tokens:
Bogdan Egikov wrote in #note-11:
I have implemented pillar 1 (personal access tokens) together with pillars 2 (scoped permissions)
and 4 (structured audit logging) as a single patch against current trunk. Attached:.personal-access-tokens-43881.patchPersonal access tokens
- New
personal_access_tokenstable (one migration) and model: multiple named tokens per user, each with a mandatory expiration date. Only the SHA256 digest of the value is stored (same strategy as the existing Doorkeeperhash_token_secretsconfiguration); thermpat_-prefixed value is displayed exactly once, at creation.- Self-service UI under My account (list / create / revoke), protected by sudo mode; throttled last-used tracking; a new
personal_access_token_max_lifetimesetting (Administration -> Settings -> Integrations tab,format: int, 0 = no limit, security-notified). The new-token form clamps its default expiration to this policy.- Fully backward compatible:
find_current_usertries the token digest first and falls back to the unchanged legacy API key, across all three transports (header,keyparameter, HTTP Basic username). Existing keys and integrations are not affected - same coexistence approach as the OAuth provider introduction in 6.1.0.- A tested
PersonalAccessToken.import_legacy_api_tokens!is included but deliberately not invoked: legacy plaintext keys can be converted to hashed tokens server-side without invalidating them (lookup is by digest), so a future release can retire plaintext keys with a data migration in the style of SaltUserPasswords (20110223180953).Scoped permissions
- Optional
scopescolumn (space-separated permission names, blank = full access). Enforcement reuses the existing OAuth machinery: scopes are assigned toUser#oauth_scope, so theRole#allowed_to?intersection and theadminpseudo-scope apply unchanged, and public permissions are force-included like OAuth applications.- Note: this inherits the open defect #44271 (issue attribute editing goes through
Issue#user_tracker_permission?, bypassing the scope intersection). The patch pins that behavior with a clearly-labelled test that will start failing once #44271 is fixed, so both mechanisms pick up the fix together.
Holger Just wrote in #note-12:
Most of the functionality of your new personal access tokens seems to mirror what we already have with the oauth applications (e.g. restricted scopes or token live times) as implemented in #24808. As such, I'm not sure if it's actual a good idea to duplicate most of this again. Instead, I would prefer an approach where we adapt / extend the existing oauth applications so that we could issue long-lived access tokens from there.
Files
Related issues
Updated by Marius BĂLTEANU 1 day ago
- Related to Feature #43881: Strengthen API authentication: API tokens with expiration, scopes, rate limiting and audit logging added
Updated by Marius BĂLTEANU 1 day ago
- File 0001-Implement-personal-access-tokens-43881.patch 0001-Implement-personal-access-tokens-43881.patch added
I extracted from the initial patch posted by Bogdan Egikov in #43881 only the part related to Personal Access Tokens to ease the review of the changes.
Updated by Bogdan Egikov 1 day ago
Thanks for splitting this out, Marius BĂLTEANU – happy to keep iterating on it here.
If any changes are needed to get this ready for a release, notify me and I'll prepare them.
Updated by Marius BĂLTEANU 1 day ago
Holger Just wrote:
Most of the functionality of your new personal access tokens seems to mirror what we already have with the oauth applications (e.g. restricted scopes or token live times) as implemented in #24808. As such, I'm not sure if it's actual a good idea to duplicate most of this again. Instead, I would prefer an approach where we adapt / extend the existing oauth applications so that we could issue long-lived access tokens from there.
I took a look at both implementations and I think we can reuse some existing code (UI, shared permission scope definitions, etc.), but I don't think reusing Doorkeeper's tables and models is the best option for us in the long term. Also, conceptually, OAuth tokens are designed for third-party apps (client IDs, secrets, redirect URIs, refresh tokens), whereas PATs are designed directly for users.
I personally prefer having a dedicated table for PATs so we don't depend on, modify, or couple our implementation with an external gem over which we don't have full control. Additionally, PATs require their own specific fields—such as a friendly name, hashed storage, expiration date, and a last-used timestamp—which are not currently provided by Doorkeeper.
Once we agree on the direction (using our own dedicated PAT table vs OAuth tables), we can move forward with discussions regarding which code can be reused, what cannot, and what else is needed to ship this feature in the next major release.
Updated by Marius BĂLTEANU 1 day ago
Bogdan Egikov wrote in #note-4:
If any changes are needed to get this ready for a release, notify me and I'll prepare them.
We should wait first to reach a common consensus regarding the overall architectural direction before changing any code.