Manage Project-Scoped Identity Mappings

Starting from Artifactory version 7.94, you can create identity mappings associated with a specific project. Project Admins can manage identity mappings scoped to their own project without requiring Platform Admin assistance.

This page describes how to manage project-scoped OIDC identity mappings using the REST API, which is essential for automating CI/CD onboarding at scale.

For more information, see OpenID Connect Integration.

Prerequisites

  • An OIDC provider integration must already be configured in the JFrog Platform. See Configure an OIDC Integration.
  • You must authenticate with a token that has Project Admin privileges for the target project, including the manage-resources action.

Understanding Global and Project-Scoped Mappings

The following table compares global and project-scoped identity mappings.

AspectGlobal MappingProject-Scoped Mapping
Who can createPlatform Admin onlyPlatform Admin or Project Admin with manage-resources
Scope formatapplied-permissions/groups:... or applied-permissions/user:...applied-permissions/roles:{project_key}:{role}
VisibilityVisible to all. May be hidden from Project Admins through configurationVisible to Platform Admins and the project's Project Admins
Precedence during token exchangeLower priority when project_key is supplied in the exchangeHigher priority when project_key is supplied in the exchange
Use caseShared CI/CD access for multiple projectsDedicated CI/CD access for a specific project
📘

Note

The project scope of an identity mapping is determined entirely by the token_spec.scope field. There is no separate project_key input field on the create or update API. The project_key in the response is derived from the scope.

How Project Key Is Determined

The platform extracts the identity mapping's project key from the token_spec.scope field:

  • If the scope contains applied-permissions/roles:{project_key}:{roles}, the project key is extracted from the middle segment.
  • If the scope contains applied-permissions/groups:... or applied-permissions/user:..., the mapping is global and has no project key.
  • Only one project key is allowed per mapping. Specifying roles for multiple projects in the same scope isn't supported.

For general scope format details, see Create Scoped Token.

Step 1: Create a Project-Scoped Identity Mapping

Use the Create an Identity Mapping API.

curl -X POST "https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <project-admin-token>" \
  -d '{
    "name": "my-project-ci-deploy",
    "description": "CI/CD deploy mapping for my-project",
    "claims": {
      "repository": "my-org/my-repo",
      "ref": "refs/heads/main"
    },
    "token_spec": {
      "scope": "applied-permissions/roles:my-project:\"Developer\"",
      "audience": "jfrt@* jfac@*",
      "expires_in": 3600
    },
    "priority": 1
  }'
📘

Note

The scope format for project roles is applied-permissions/roles:{project_key}:"{Role1}","{Role2}". Role names must be comma-separated. Enclose multi-word role names in double quotes.

Available Project Roles

You can assign one or more project roles in the scope. The roles must be defined in the target project. Common roles include:

  • Developer: Read and deploy artifacts
  • Project Admin: Full project management
  • Release Manager: Manage releases and promotions
  • Custom roles: Roles defined for the project

Example with multiple roles:

applied-permissions/roles:my-project:"Developer","Release Manager"

Step 2: Exchange an OIDC Token with Project Scope

When your CI/CD pipeline requests a token, include the project_key parameter to ensure project-scoped mappings take precedence:

curl -X POST "https://{jfrog_url}/access/api/v1/oidc/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "subject_token_type": "urn:ietf:params:oauth:token-type:id_token",
    "subject_token": "<OIDC_ID_TOKEN>",
    "provider_name": "{provider_name}",
    "project_key": "my-project"
  }'

The returned access token carries the permissions defined by the matched identity mapping's token_spec.

📘

Note

The token exchange API doesn't require JFrog authentication. The platform authorizes the request by validating the external OIDC token and matching its claims against configured identity mappings.

Using JFrog CLI

You can also exchange tokens using the JFrog CLI:

jf eot {provider_name} {oidc_token_id} \
  --url=https://{jfrog_url} \
  --project=my-project

For more information, see Exchange OIDC Token with the JFrog CLI.

Step 3: List Project-Scoped Identity Mappings

Use the Get all Identity Mappings API with the project_key query parameter:

curl -X GET "https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings?project_key=my-project" \
  -H "Authorization: Bearer <project-admin-token>"

Step 4: Update a Project-Scoped Identity Mapping

Use the Update OIDC Identity Mapping API:

curl -X PUT "https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings/{mapping_name}" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <project-admin-token>" \
  -d '{
    "name": "my-project-ci-deploy",
    "description": "Updated description",
    "claims": {
      "repository": "my-org/my-repo",
      "ref": "refs/heads/*"
    },
    "token_spec": {
      "scope": "applied-permissions/roles:my-project:\"Developer\"",
      "audience": "jfrt@* jfac@*",
      "expires_in": 7200
    },
    "priority": 1
  }'
📘

Note

The project scope of an identity mapping can't be changed after creation. The token_spec.scope must imply the same project key as the existing mapping. Attempting to change the project key returns 400 Bad Request.

Step 5: Delete a Project-Scoped Identity Mapping

Use the Delete Identity Mapping API:

curl -X DELETE "https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings/{mapping_name}" \
  -H "Authorization: Bearer <project-admin-token>"

Project Admins can delete project-scoped identity mappings for their own project. Deleting global identity mappings requires Platform Admin privileges.

Identity Mapping Precedence Rules

When a token exchange request includes a project_key, the system uses the following precedence rules to select the matching identity mapping:

  1. Project scope first: Identity mappings scoped to the specified project are evaluated before global mappings.
  2. Priority within scope tier: Within each tier (project-scoped or global), mappings with a lower numeric priority value are evaluated first (priority 1 before priority 10).
  3. Creation time tiebreaker: If two mappings have the same priority, the one created earlier takes precedence.
  4. First match wins: The first mapping whose claim filter matches the incoming JWT claims is selected.

When project_key isn't supplied in the token exchange request, all mappings, global and project-scoped, compete equally based on priority and creation time.

📘

Note

If a global mapping has priority 1 and a project mapping has priority 5, the project mapping still wins when project_key is supplied, because project scope is the first sort key.

Permission Model Summary

The following table summarizes who can perform each identity mapping operation.

OperationPlatform AdminProject Admin with manage-resourcesProject Admin without manage-resources
Create project-scoped mappingYesYes, own project onlyNo, returns 403
Create global mappingYesNo, returns 403No, returns 403
Update project-scoped mappingYesYes, own project onlyNo, returns 403
Update global mappingYesNo, returns 403No, returns 403
List project-scoped mappingsYes, all projectsYes, own project onlyYes, own project only
List global mappingsYesDepends on global mapping visibility configurationDepends on configuration
Delete project-scoped mappingYesYes, own project onlyNo, returns 403
Delete global mappingYesNo, returns 403No, returns 403
Token exchangeNo authentication requiredNo authentication requiredNo authentication required