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-resourcesaction.
Understanding Global and Project-Scoped Mappings
The following table compares global and project-scoped identity mappings.
| Aspect | Global Mapping | Project-Scoped Mapping |
|---|---|---|
| Who can create | Platform Admin only | Platform Admin or Project Admin with manage-resources |
| Scope format | applied-permissions/groups:... or applied-permissions/user:... | applied-permissions/roles:{project_key}:{role} |
| Visibility | Visible to all. May be hidden from Project Admins through configuration | Visible to Platform Admins and the project's Project Admins |
| Precedence during token exchange | Lower priority when project_key is supplied in the exchange | Higher priority when project_key is supplied in the exchange |
| Use case | Shared CI/CD access for multiple projects | Dedicated CI/CD access for a specific project |
Note
The project scope of an identity mapping is determined entirely by the
token_spec.scopefield. There is no separateproject_keyinput field on the create or update API. Theproject_keyin 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:...orapplied-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 artifactsProject Admin: Full project managementRelease 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-projectFor 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.scopemust imply the same project key as the existing mapping. Attempting to change the project key returns400 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:
- Project scope first: Identity mappings scoped to the specified project are evaluated before global mappings.
- 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).
- Creation time tiebreaker: If two mappings have the same priority, the one created earlier takes precedence.
- 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_keyis supplied, because project scope is the first sort key.
Permission Model Summary
The following table summarizes who can perform each identity mapping operation.
| Operation | Platform Admin | Project Admin with manage-resources | Project Admin without manage-resources |
|---|---|---|---|
| Create project-scoped mapping | Yes | Yes, own project only | No, returns 403 |
| Create global mapping | Yes | No, returns 403 | No, returns 403 |
| Update project-scoped mapping | Yes | Yes, own project only | No, returns 403 |
| Update global mapping | Yes | No, returns 403 | No, returns 403 |
| List project-scoped mappings | Yes, all projects | Yes, own project only | Yes, own project only |
| List global mappings | Yes | Depends on global mapping visibility configuration | Depends on configuration |
| Delete project-scoped mapping | Yes | Yes, own project only | No, returns 403 |
| Delete global mapping | Yes | No, returns 403 | No, returns 403 |
| Token exchange | No authentication required | No authentication required | No authentication required |
