Overview
An OIDC identity mapping is a rule that lets the JFrog Platform exchange a token from a trusted external provider (such as GitHub Actions) for a JFrog Platform access token. When an incoming token's claims match the mapping, the platform issues a scoped access token according to the mapping's token settings.
Identity mappings exist at two levels:
- Global mappings apply across the entire platform and can be used by all projects.
- Project mappings apply only to a single, specified project.
In the JFrog UI, the level is determined by the scope you are working in when you open the dialog, so no project field appears on the form. When working through the REST API, the project is set explicitly using a query parameter. This article describes how to create a project-scoped mapping via the API.
Prerequisites
- Artifactory version 7.94 or later (project-level identity mappings were introduced in 7.94).
- An existing OIDC configuration (provider).
- Platform Admin privileges or Project Admin privileges for the target project.
- A valid access token to authenticate the API call.
Step 1: Identify your endpoint and parameters
The base endpoint for creating an identity mapping is:
POST
https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings
To scope the mapping to a project, append the projectKey query parameter:
POST
https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings?projectKey={project_key}
Replace the placeholders with your values:
- {jfrog_url} — Your JFrog Platform URL.
- {provider_name} — The name of the existing OIDC configuration.
- {project_key} — The key of the target project.
The projectKey must be passed as a query parameter on the URL. If the project value is placed only inside the JSON body, it is ignored, and the mapping is created as a global mapping instead.
Step 2: Build the request body
The request body defines the mapping. The claims object is the matching filter: the mapping is applied only when an incoming token's claims match these values. The token_spec object defines the access token that is issued on a successful match.
An example is given below:
{
"name": "anjali-testing",
"priority": 1,
"description": "Project-scoped OIDC mapping for devops",
"claims": {
"sub": "repo:testrepo/jfrog-github-oidc-example:*",
"ref": "refs/heads/main",
"iss": "https://token.actions.githubusercontent.com"
},
"token_spec": {
"scope": "applied-permissions/roles:devops:\"Developer\"",
"username": "githubtest",
"audience": "*@*",
"expires_in": 60
}
}
Parameter notes:
- name — a unique name for the mapping.
- priority — lower numbers indicate higher priority. Project mappings take precedence over global mappings.
- claims — the OIDC claims to match. iss is the issuer (for GitHub Actions, always https://token.actions.githubusercontent.com), sub identifies the repository and context, and ref restricts the match to a specific branch. Every claim listed must match, so adding more claims makes the rule stricter.
- token_spec.scope — for a project-scoped role, use the form applied-permissions/roles:{project_key}:"RoleName". A username is required when using a role scope.
- expires_in — token lifetime in seconds (the UI displays this value in minutes).
Step 3: Send the request
The syntax for the command:
curl -X POST \
"https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings?projectKey={project_key}" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "<mapping_name>",
"priority": <priority_number>,
"description": "<description>",
"claims": {
"<claim_key>": "<claim_value>"
},
"token_spec": {
"scope": "<token_scope>",
"username": "<username>",
"audience": "<audience>",
"expires_in": <expiry_in_seconds>
}
}'
The following example creates a mapping named anjali-testing under the provider oidctest, scoped to the devops project:
curl -X POST \
"https://{jfrog_url}/access/api/v1/oidc/oidctest/identity_mappings?projectKey=devops" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "anjali-testing",
"priority": 1,
"description": "Project-scoped OIDC mapping for devops",
"claims": {
"sub": "repo:testrepo/jfrog-github-oidc-example:*",
"ref": "refs/heads/main",
"iss": "https://token.actions.githubusercontent.com"
},
"token_spec": {
"scope": "applied-permissions/roles:devops:\"Developer\"",
"username": "githubtest",
"audience": "*@*",
"expires_in": 60
}
}'
Step 4: Verify the mapping was created at the project level
Confirm the mapping is scoped correctly rather than created globally:
- In the UI, select the target project, then go to the Administration module and open the OIDC integration's identity mappings. The new mapping should appear under the project's scope, not only under the platform-wide list.
- A mapping that mistakenly appears only under Platform Administration was created globally. This usually means the projectKey was omitted from the URL or placed only in the body. Recreate it with projectKey on the URL.
Updating a Project-Specific Identity Mapping
To modify an existing mapping, send a PUT request that targets the mapping by name in the path. Keep the projectKey query parameter so the project-scoped mapping is updated rather than a same-named global mapping. The body accepts name, description, claims, token_spec and priority.
Syntax:
curl -X PUT \
"https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings/{mapping_name}?projectKey={project_key}" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "<mapping_name>",
"priority": <priority_number>,
"description": "<description>",
"claims": {
"<claim_key>": "<claim_value>"
},
"token_spec": {
"scope": "<token_scope>",
"username": "<username>",
"audience": "<audience>",
"expires_in": <expiry_in_seconds>
}
}'
Example: Update the anjali-testing mapping under provider oidctest in the devops project:
curl -X PUT \
"https://{jfrog_url}/access/api/v1/oidc/oidctest/identity_mappings/anjali-testing?projectKey=devops" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "anjali-testing",
"priority": 2,
"description": "Updated project-scoped OIDC mapping for devops",
"claims": {
"sub": "repo:testrepo/jfrog-github-oidc-example:*",
"ref": "refs/heads/release",
"iss": "https://token.actions.githubusercontent.com"
},
"token_spec": {
"scope": "applied-permissions/roles:devops:\"Developer\"",
"username": "githubtest",
"audience": "*@*",
"expires_in": 120
}
}'
Deleting a Project-Specific Identity Mapping
To remove a mapping, send a DELETE request to the same resource path, identifying the mapping by name. Keep the projectKey query parameter so the project-scoped mapping is removed rather than a same-named global mapping.
Syntax:
curl -X DELETE \
"https://{jfrog_url}/access/api/v1/oidc/{provider_name}/identity_mappings/{mapping_name}?projectKey={project_key}" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
Example: delete the anjali-testing mapping under provider oidctest in the devops project:
curl -X DELETE \
"https://{jfrog_url}/access/api/v1/oidc/oidctest/identity_mappings/anjali-testing?projectKey=devops" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
Common Issues
- Mapping created globally instead of at the project level — Ensure projectKey is included as a query parameter on the request URL, not in the JSON body.
- Permission denied — Confirm the access token belongs to a Platform Admin or a Project Admin for the target project.
- Mapping never matches an incoming token — Verify the claims values are a subset of the claims actually present in the incoming token. Inspect a decoded OIDC token from a workflow run to see the available claims, and match on the ones that give the intended scope (sub alone is often sufficient).