An Artifactory token that can deploy to a release repository is a key to every build that pulls from it, yet most organisations still issue these tokens for a year or forever and paste them into CI variables. JFrog Artifactory and the wider JFrog Platform authenticate people, build agents and platform services with access tokens, and the platform offers scopes, audiences, expiry limits, refresh controls and OIDC token exchange that, used well, make those tokens short-lived and narrow. This guide explains how the token model actually works (including the thresholds that decide whether a token can be revoked at all), which admin settings matter, how to move CI pipelines off static tokens, and what to log and measure. It is for platform, DevSecOps and identity teams; behaviour is from JFrog documentation, so check your release before changing settings.
Key takeaways
- Every token is scoped, but not every token is narrow. Since Artifactory 7.21.1 all access tokens carry a scope; the default
applied-permissions/userstill gives the token everything its user can do, so group-scoped tokens and dedicated service users are the real control. - Short tokens may not be revocable. Tokens with a lifetime below the
revocable-expiry-threshold(default 6 hours) cannot be revoked; short lifetime is the control for those, and long-lived tokens must be revocable and inventoried. - The default lifetime is long. The platform's Default Token Expiration is 31,536,000 seconds (365 days) and Max Token Expiration defaults to 0 (no limit), so non-expiring tokens are allowed until an administrator sets a cap.
- OIDC exchange removes stored secrets from CI. Identity mappings exchange a GitHub, Azure DevOps, GitLab or other OIDC ID token for an access token valid for at most 1,440 minutes; define claims on every mapping or anyone who can reach the integration may get a token.
- API keys are end of life. JFrog ended API key support at the end of Q4 2024; find remaining use in the access log and turn on the settings that block API key creation and authentication.
How identity and access work in Artifactory
Authentication and token issuance in the JFrog Platform sit in the JFrog Access service, which issues JSON Web Tokens (JWTs) signed by the platform. Each token has a subject (the user it acts as; if the user does not exist, a transient user is created for the request), an issuer (the cluster that created it), an audience (the service IDs that will accept it, default *@*) and a scope that decides which permissions apply. Authorisation itself comes from users, groups and permission targets on repositories, builds and release bundles, so a token is never more powerful than the user or groups it maps to, but it is often exactly as powerful.
Token types
| Token type | Who can create it | Typical use | Security notes |
|---|---|---|---|
| Identity token (user-scoped) | Any user, for themselves (profile page or REST API) | Developer CLI, package manager clients | Stored hashed, shown once, revoked automatically when the user is deleted or disabled. Inherits all the user's permissions. |
| User-scoped token (admin-issued) | Administrators, for any user | Service users for automation | Admins can set any subject, so a token can act as a user who has never logged in. |
| Group-scoped token | Artifactory administrators only | CI jobs needing a fixed permission set | Scope applied-permissions/groups:group_1,group_2; no real user required, which keeps the permission set explicit. |
| Admin token | Administrators (Generate Admin Token) | Platform services and admin automation | Full administrative power. Treat as a privileged credential with an owner and an expiry. |
| Project admin token | Project admins, for their projects | Project-level automation | Scope applied-permissions/roles:<project-key>:<role>; JFrog caps lifetime at 1,440 minutes. |
| Reference token | Created alongside any token (include_reference_token, CLI --reference) | Clients that cannot handle long JWTs | A short alias for the full JWT. Not supported in a Circle of Trust. Treat it exactly like the token it points to. |
| Pairing, master and binding tokens | Platform administrators | Trust between JFrog services and platform deployments | Pairing tokens default to 300 seconds and are meant for single use; revoking the master token ends the trust relationship. |
Scope syntax that matters
applied-permissions/user: the default scope in the Create Token API. The token acts with all of the subject user's permissions, and at authentication it also picks up every local group marked to automatically join new users (Auto Join groups).applied-permissions/groups:...: the token carries only the listed groups' permissions. JFrog notes that tokens without the user scope get only their explicitly mapped groups, which is what you want for automation.applied-permissions/roles:<project>:<role>: project role tokens, limited to one JFrog Project.- Audience: restrict tokens to the service IDs that need them (for Artifactory, get the ID from the Get Service ID REST API) instead of leaving
*@*, so a token stolen from one instance is not accepted by others in the same trust domain.
Admin roles and privileged access
- Platform administrators: can issue admin tokens, tokens for any subject, group-scoped tokens and non-expiring tokens (
expires_in=0, or--expiry=0in the JFrog CLI). Keep the number of admin accounts small, put them behind your identity provider with phishing-resistant MFA, and do not use admin accounts for day-to-day package work. See the Privileged Access Management Guide. - Project admins: can create project tokens and, with the manage-resources action, manage project-scoped OIDC identity mappings. Turn on Hide Global Identity Mappings From Project Admins so they see only their own projects' mappings.
- Every user: can create identity tokens. The
token.max-expirysetting (Access configuration) and the Max Token Expiration setting (UI) are what stop a user minting a token that outlives their employment.
Two further settings shape privileged access. Disable Basic Authentication (Artifactory 7.104.0 and later, applies when external authentication is used) stops password logins for SSO users, with an explicit allow list for internal users who still need it. Enable Token Generation via API decides whether basic-authenticated users can mint tokens through the REST API; if a password can create a token, a stolen password becomes a stolen long-lived token. Where you use SAML or LDAP, also enable SCIM: JFrog documents that without SCIM an external user who has been removed can still refresh a refreshable token.
Integrations, API tokens and service accounts
Most Artifactory tokens belong to machines: CI runners, deployment tools, Kubernetes image pull secrets, security scanners and SCIM provisioning. These are non-human identities and should follow the same lifecycle as any other. See the Service Account Security Guide. Where Artifactory proxies or mirrors public registries, the upstream publishing credentials carry the same risks: see the npm Tokens Security Guide and the Docker Hub Tokens Security Guide.
Choosing the credential for a machine
| Option | Lifetime | Revocable? | Best for | Trade-off |
|---|---|---|---|---|
| OIDC token exchange (identity mapping) | Set per mapping, maximum 1,440 minutes | Short tokens are not individually revocable; disable the mapping instead | GitHub Actions, Azure DevOps, GitLab, other OIDC-capable CI; AWS IAM roles via SigV4 exchange | Requires Enterprise X or Enterprise+ licence; claim design needs care |
| Group-scoped access token, short expiry, refreshable | Hours to days, refreshed by the job or a broker | Yes, if above the revocable threshold | Tools without OIDC that can run a refresh | Refresh token becomes the secret to protect; only the issuing instance or cluster can refresh |
| Group-scoped access token, fixed expiry | 30 to 90 days, rotated by a secrets manager | Yes | Image pull secrets, third-party scanners | Still a static secret; needs rotation automation and an owner |
| Identity token of a human user | Platform default unless capped | Yes | The person's own CLI only | Never use in shared automation: it carries all the user's rights and dies with their account |
| API key | Never expires | Only by removal | Nothing: end of life | Retrievable, no lifecycle management |
OIDC identity mappings done safely
With OIDC integration the CI job asks its provider for an ID token and posts it to /access/api/v1/oidc/token with the token-exchange grant and the provider_name. JFrog Access checks the signature against the provider's JSON Web Key Set, validates the audience and the claims in the matching identity mapping, and returns an access token whose lifetime is the mapping's expiry. JFrog's guidance:
- Always set claims JSON: JFrog warns that a mapping with no claims lets anyone who knows the target obtain access. For GitHub, match on repository and, ideally, workflow or environment, not on organisation alone, and avoid the permissive configuration option.
- Order by priority: lower numbers win. Give the most privileged mappings the highest priority and the strictest claims so a broad, low-privilege mapping cannot shadow them or be shadowed by them by accident.
- Use group scope, blank username: leaving the username blank yields a synthetic subject with only the mapped groups, avoiding Auto Join groups that a transient named user would inherit.
- Minimise workflow permissions: grant only
id-token: writein the workflow and stop storing JFrog credentials in CI settings. - Keep tokens out of logs: log
sub,audandissfor debugging, never the ID token or access token.
For the provider side, see the GitHub and GitHub Actions Security Guide and the CI/CD Pipeline Identity Security Guide.
Expiry, refresh and revocation: the mechanics
| Setting | Where | Default | Effect and recommendation |
|---|---|---|---|
| Default Token Expiration | Security, General (UI) | 31,536,000 s (365 days) | Lifetime when a creator does not specify one. Lower it to match policy, for example 30 to 90 days for user tokens. |
Max Token Expiration / token.max-expiry | UI / access.config.latest.yml | 0 (no limit) | Above 0, non-admins cannot create non-expiring tokens. Must be higher than the default expiry. Set it. |
revocable-expiry-threshold | Access YAML | 6 hours | Tokens shorter than this cannot be revoked. JFrog advises against values under 2 hours; 0 makes all tokens revocable at a performance cost; negative values allow non-revocable long tokens. |
persistent-expiry-threshold | Access YAML | 3 hours | Tokens shorter than this are not stored in the database, so they will not appear in token listings. Must be no greater than the revocable threshold. |
token.allow-refreshable | Access YAML | Refreshable allowed | Set to false if nothing needs refresh; otherwise allow and keep access tokens short. |
token.refresh-expiry | Access YAML | 24 hours | Grace period in which an expired refreshable token can still be refreshed. |
force_revocable | Create Token API | false | Marks a token revocable regardless of the threshold (from 7.50.x); useful for a short token you might need to kill. |
| Token expiry notifications | Security, General | Off | Email owners before expiry so rotation is planned, not an outage. |
- Revocation scope: a token can be revoked only on the instance that issued it, unless Access Federation is configured (Enterprise+). Record the issuing instance in your inventory.
- Revocation routes: the UI token list, the Revoke Token by ID and Revoke Token by Value REST APIs, and, as a last resort, resetting the token signing certificates, which revokes every generated token on the platform and should be in your incident runbook as a break-glass step.
For the general principles behind these numbers, see the Token Lifetime Policy Design Guide.
Logging and detection
- Audit trail: self-hosted deployments write
$JFROG_HOME/artifactory/var/log/access-security-audit.log, enabled by default and controlled bysecurity.audit.enabled. It records create, update and delete events (C, U, D) for users (USR), groups (GRP), permissions (PRM) and, from Artifactory 7.131.0, tokens (TKN), with date, trace ID, user IP, user, logged principal and the data changed. Default retention is 10 files of 100 MB; forward it to your SIEM rather than raising local retention. - Access log:
var/log/artifactory-access.logrecords accepted and denied logins and the authentication method, which is where JFrog tells you to find remaining API key use.
Detections worth building
| Signal | Source | Why it matters | ATT&CK |
|---|---|---|---|
| Token created with no expiry or with admin scope | access-security-audit.log (TKN, C) | Persistence through a long-lived privileged credential | T1098 Account Manipulation |
| Token used from an IP or ASN outside known CI and office ranges | artifactory-access.log, proxy logs | Stolen token replayed by an outsider | T1550.001 Application Access Token |
| Deploy or delete to a release repository by an identity that normally only reads | Request and audit logs | Artifact tampering in the supply chain | T1195.002 Compromise Software Supply Chain |
| Burst of failed logins or 401s against one user | artifactory-access.log | Password guessing ahead of token minting | T1110 Brute Force |
| New or changed OIDC identity mapping, or a mapping with empty claims | Audit trail, configuration export review | A backdoor route to tokens without any stored secret | T1556 Modify Authentication Process |
| Artifactory tokens found in repositories, images or CI logs | Secret scanning | Exposure before use | T1552.001 Credentials In Files |
Pair these detections with the Git Secret Scanning Guide.
Metrics
- Non-expiring tokens: count of tokens with no expiry, target zero outside documented platform pairing.
- Median machine token lifetime: for CI, measured in minutes or hours once OIDC is in place.
- Pipelines on OIDC: percentage of pipelines that authenticate by token exchange rather than a stored token.
- Owner coverage: percentage of long-lived tokens with a named owner and a description (the API allows up to 1,024 characters).
- Mean time to revoke: from a secret-scanning alert on an Artifactory token to revocation.
Hardening baseline and rollout
- Inventory first. Export the token list (UI and REST), the access log for API key use over about three months (JFrog's own suggestion), and every OIDC identity mapping. Record subject, scope, audience, expiry, issuing instance and owner. Tokens under the persistent threshold are not listed.
- Kill API keys. Notify owners, migrate them to identity or reference tokens, then set
security.authentication.disable-api-key-creationandsecurity.authentication.disable-api-key-authenticationto true (self-hosted) or tick Disable API Key Usage (cloud, 7.107.1 and later). Roll back by unsetting the authentication flag for a short, named window only. - Cap lifetimes. Set Default Token Expiration and Max Token Expiration (
token.max-expiry) to policy values; leaverevocable-expiry-thresholdandpersistent-expiry-thresholdat or above their recommended minimums. Test in a non-production instance, as an existing client that requests a longer expiry will start failing. - Create service identities. Replace tokens borrowed from people with group-scoped tokens per pipeline or system, with audience limited and a description that names the owner.
- Move CI to OIDC in rings. Pilot one repository per CI platform, then one team, then all. Keep the old static token for one release cycle as the rollback, then revoke it.
- Close the side doors. Disable anonymous access (JFrog advises against it), enable Hide Existence of Unauthorized Resources, Disable Basic Authentication for SSO users, restrict Enable Token Generation via API, enable SCIM with your identity provider, and require MFA for any remaining local accounts.
- Wire detection. Ship audit and access logs to the SIEM and turn on the detections and metrics above before declaring done.
Small team or large enterprise?
- Small teams on a single instance get most of the value from three changes: cap expiry, stop using personal tokens in CI, and adopt OIDC if the licence includes it. If it does not, use group-scoped tokens stored in the CI platform's secret store and rotated on a schedule.
- Large or multi-site deployments need consistent settings across instances, Access Federation if tokens must be revocable everywhere, project-scoped identity mappings per team, and token issuance moved into a secrets manager or broker. See the Secrets Management Guide.
Common misconfigurations
- A developer's identity token in the CI variables: it carries every right the developer has, survives as long as the platform default allows and stops working the day they leave, so teams respond by making it non-expiring. The Codecov breach showed what happens when a compromised CI step reads every environment variable: any long-lived registry token in that environment was exposed.
- Short tokens assumed to be revocable: a team sets 4-hour tokens for incident safety, not realising that anything below the 6-hour default revocable threshold cannot be revoked. Either accept that the lifetime is the control or set
force_revocable. - OIDC mappings that trust a whole organisation: claims that match only the GitHub organisation, or no claims at all, let any repository (including a fork workflow or a newly created repository) obtain the mapped permissions.
- Auto Join groups with write rights: user-scoped and named-user OIDC tokens pick up every Auto Join group, so a group meant for onboarding humans quietly grants deploy rights to automation.
- Admin tokens for routine jobs: a nightly clean-up script running with an admin token means one leaked file gives full control of repositories, users and permissions.
- Audience left at
*@*: in a Circle of Trust, a token minted on a test instance is accepted by production.
Framework mapping
| Control area | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | CIS Controls v8.1 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|---|
| Token lifetime, rotation and storage | IA-5 Authenticator Management | PR.AA-01 | Control 5 Account Management | A.5.17 Authentication information |
| Scopes, group tokens, admin token limits | AC-6, AC-6(5) | PR.AA-05 | Control 6 Access Control Management | A.8.2 Privileged access rights |
| CI and service authentication (OIDC exchange) | IA-9 Service Identification and Authentication | PR.AA-03 | Control 6 | A.8.5 Secure authentication |
| Disabling leavers' tokens, SCIM | AC-2, AC-2(3) | PR.AA-01 | Control 5 | A.5.18 Access rights |
| Audit and access logging | AU-2, AU-6 | PR.PS-04, DE.CM-03 | Control 8 Audit Log Management | A.8.15 Logging |
For the supply chain view of artifact repositories, see the Software Supply Chain Security Guide.
Practitioner checklist
- Export every token, API key user and OIDC identity mapping, and give each long-lived token a named owner.
- Set Default Token Expiration and Max Token Expiration (
token.max-expiry) so non-admins cannot create non-expiring tokens. - Disable API key creation and authentication after migrating the remaining users.
- Replace personal tokens in automation with group-scoped tokens limited by audience.
- Move CI to OIDC token exchange with claims on every mapping and lifetimes of an hour or less where builds allow.
- Keep
revocable-expiry-thresholdat 2 hours or more and useforce_revocablewhere a short token must still be killable. - Disable anonymous access, restrict basic authentication and token generation via API, and enable SCIM.
- Limit admin tokens to platform services, each with an expiry and a ticket reference.
- Forward access-security-audit.log and artifactory-access.log to the SIEM and alert on non-expiring and admin token creation.
- Add token revocation, mapping disablement and certificate reset to the incident runbook.
Standards and references
- JFrog: Access Tokens
- JFrog: Create Token REST API
- JFrog: OpenID Connect Integration
- JFrog: Security Configuration
- JFrog: Identity Tokens
- JFrog: API Key
- JFrog: Audit Trail Log
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: CI/CD Pipeline Identity Security Guide · Container Registry Security Guide · npm Tokens Security Guide · Docker Hub Tokens Security Guide