Skip to content

[18.0][ADD] auth_api_key_provisioning: mint scoped API keys for other users#947

Draft
manana2520 wants to merge 1 commit into
OCA:18.0from
manana2520:18.0-add-auth_api_key_provisioning
Draft

[18.0][ADD] auth_api_key_provisioning: mint scoped API keys for other users#947
manana2520 wants to merge 1 commit into
OCA:18.0from
manana2520:18.0-add-auth_api_key_provisioning

Conversation

@manana2520

Copy link
Copy Markdown

New module: auth_api_key_provisioning

Hardened, OCA-packaged follow-up to the proposal in #946 (closed without comment).
Rather than re-asking in an issue, here is the actual code for review.

A trusted, least-privilege provisioning/service account can mint a short-lived,
rpc-scoped API key on behalf of another internal user, over RPC. This enables
delegated per-user identity: an integration (MCP server, AI agent, backend service)
acts as the end user — with that user's own record rules and correct
create_uid/write_uid — instead of as one shared service account.

Stock Odoo has no supported way to mint an API key for another user over RPC
(res.users.apikeys.generate is not an RPC method; _generate is private). This module
adds two narrow, group-gated methods on res.users plus an auditable log.

Public API

  • res.users.mint_apikey(name=None, ttl_days=None) -> str (called on the target recordset)
  • res.users.revoke_provisioned_apikeys() -> int

Security model (please scrutinise)

  • Caller gating: dedicated API Key Provisioning group — not base.group_system.
  • Target allowlist: only users in API Key Mintable Target (allowlist, not blocklist,
    because custom modules add their own high-privilege groups a blocklist can't enumerate).
  • Elevated targets always refused: superuser, group_system, group_erp_manager;
    also portal/share and archived users.
  • Privilege-drift / TOCTOU protection: an API key carries no permission snapshot — it
    authenticates with the user's current groups. So if a target with provisioned keys is
    later promoted into an elevated group (user-side or group-side) or archived, its
    provisioned keys are revoked immediately, with a daily cron as a backstop for paths that
    bypass the ORM hooks.
  • Bounded lifetime: keys are rpc-scoped and expiring; TTL defaults to 30 days,
    clamped to a configurable max (90), with an absolute code ceiling.
  • Auditable + provenance-based revocation: every mint is logged (who/for-whom/when);
    revocation is by stored link, never by name matching.

Non-goals / residual risks (documented)

  • Not interactive UI impersonation (cf. impersonate_login) — this is a programmatic
    credential, no session.
  • Like all Odoo API keys, a minted key is not invalidated by a target password reset;
    use revoke or archive on suspected compromise.
  • A compromised provisioning account can mint keys for any mintable (non-elevated) user;
    keep that group minimal and monitor the log.

Tests

mint happy-path; default + clamped TTL; caller-group gate; refusal of non-mintable /
elevated / superuser / portal / archived targets; manual revoke; revoke gate; and the
privilege-drift cases (user-side promotion, group-side promotion, archive, cron backstop).

Open questions for maintainers

  1. Interested in this living in server-auth? (Re: [18.0] New module proposal: mint a scoped API key for another user (agent/MCP per-user identity) #946.)
  2. License — set to LGPL-3 to match the auth_api_key family; happy to switch to
    AGPL-3 if you prefer.
  3. Nameauth_api_key_provisioning; open to your preference.
  4. Anything existing/in-flight to build on instead?

Draft until the CLA is confirmed and runbot is green. CLA will be signed (entity-level)
before this is marked ready.

@OCA-git-bot OCA-git-bot added series:18.0 mod:auth_api_key_provisioning Module auth_api_key_provisioning labels Jun 9, 2026
@manana2520 manana2520 force-pushed the 18.0-add-auth_api_key_provisioning branch 5 times, most recently from 8a13bc4 to f6e0dc5 Compare June 9, 2026 11:22
Admin-gated, least-privilege module that mints short-lived, rpc-scoped
API keys on behalf of another internal user, for delegated per-user
identity (MCP servers, AI agents, backend services acting as the user
with that user's own ACLs and correct create_uid).

Security model:
- caller gated on a dedicated provisioning group (not group_system)
- targets restricted to an explicit mintable allowlist group
- superuser / group_system / group_erp_manager always refused
- portal/share and archived users refused
- keys are rpc-scoped with a TTL clamped to a configurable maximum
- privilege-drift protection: provisioned keys are auto-revoked when a
  target is promoted into an elevated group (user-side or group-side)
  or archived, with a daily cron backstop
- every mint is recorded in an auditable provisioning log; revocation
  is by stored provenance, never by name matching
@manana2520 manana2520 force-pushed the 18.0-add-auth_api_key_provisioning branch from f6e0dc5 to f2013c3 Compare June 9, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod:auth_api_key_provisioning Module auth_api_key_provisioning series:18.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants