Chapter 2. Programmatic OAuth token provisioning


To create and manage organization application tokens without the UI, you can use programmatic OAuth token provisioning through the REST API. You can also enable a Tech Preview bootstrap token for zero-touch automation.

Organization OAuth applications previously required administrators to create API tokens in the Red Hat Quay UI. With programmatic token provisioning, automation tools can manage the token life cycle.

When FEATURE_PROGRAMMATIC_BOOTSTRAP is enabled, Red Hat Quay also creates a high-privilege bootstrap OAuth token on startup and writes it to a local file or Kubernetes Secret. Use the bootstrap token to create organizations, applications, and narrower-scoped tokens without interactive UI access.

Important

Programmatic bootstrap token provisioning is a Tech Preview feature in Red Hat Quay 3.18. Tech Preview features are not supported with Red Hat production service-level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using Tech Preview features in production environments. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

2.1. Programmatic bootstrap configuration fields

Use these configuration fields to control bootstrap OAuth token provisioning for automated Red Hat Quay deployments. The feature remains disabled until you enable it. Standalone deployments store the token in a local file. Red Hat Quay on OpenShift Container Platform Operator deployments store the token in a Kubernetes Secret that the Operator creates and mounts.

Table 2.1. Programmatic bootstrap fields
FieldTypeDescription

FEATURE_PROGRAMMATIC_BOOTSTRAP

Boolean

Enables programmatic bootstrap token provisioning. When true, Red Hat Quay creates a bootstrap OAuth token on startup and writes it to a local file or Kubernetes Secret. When false, Red Hat Quay revokes any existing bootstrap token on restart.

Default: false

BOOTSTRAP_TOKEN_OWNER

String

Username that owns the bootstrap OAuth application and token. Required when FEATURE_PROGRAMMATIC_BOOTSTRAP is true. The user must exist in the database and be listed in SUPER_USERS.

BOOTSTRAP_TOKEN_PATH

String

Filesystem path where the bootstrap token JSON is written on standalone and virtual machine deployments. In containerized deployments, use a mounted path that the Red Hat Quay process can write, for example /datastorage/bootstrap-token.json.

Default: /var/lib/quay/quay-machine-token.json

BOOTSTRAP_TOKEN_EXPIRATION

Integer

Bootstrap token lifetime in seconds.

Default: 3600 (60 minutes)

BOOTSTRAP_TOKEN_SCOPE

String

Space-separated OAuth scopes assigned to the bootstrap token.

Default: org:admin repo:admin repo:create repo:read repo:write super:user user:admin user:read

PROGRAMMATIC_TOKEN_K8S_SECRET

String

Kubernetes Secret name used to store the bootstrap token when Red Hat Quay runs in Kubernetes. When set, Red Hat Quay writes the token to this Secret instead of BOOTSTRAP_TOKEN_PATH. On Red Hat Quay on OpenShift Container Platform, the Operator sets this field to <quayregistry_name>-bootstrap-token when programmatic bootstrap is enabled. Do not set this field manually in Operator-managed deployments.

PROGRAMMATIC_TOKEN_K8S_KEY

String

Secret data key that stores the bootstrap token JSON. On Red Hat Quay on OpenShift Container Platform, the Operator sets this field to token.json.

Default: token.json

PROGRAMMATIC_TOKEN_K8S_NAMESPACE

String

Kubernetes namespace that contains the bootstrap token Secret. When unset, Red Hat Quay uses the pod service account namespace. On Red Hat Quay on OpenShift Container Platform, the Operator uses the QuayRegistry namespace.

PROGRAMMATIC_TOKEN_PATH

String

Operator-rendered mount path for configuration compatibility. On Red Hat Quay on OpenShift Container Platform, the Operator sets this field to /var/lib/quay/bootstrap-token/token.json. Standalone deployments use BOOTSTRAP_TOKEN_PATH for local file storage.

Programmatic bootstrap example YAML (standalone)

FEATURE_PROGRAMMATIC_BOOTSTRAP: true
SUPER_USERS:
  - quayadmin
BOOTSTRAP_TOKEN_OWNER: quayadmin
BOOTSTRAP_TOKEN_PATH: /var/lib/quay/quay-machine-token.json
BOOTSTRAP_TOKEN_EXPIRATION: 7776000
BOOTSTRAP_TOKEN_SCOPE: "org:admin repo:admin repo:create repo:read repo:write super:user user:admin user:read"

Programmatic bootstrap example YAML (Red Hat Quay on OpenShift Container Platform configBundleSecret)

FEATURE_PROGRAMMATIC_BOOTSTRAP: true
SUPER_USERS:
  - quayadmin
BOOTSTRAP_TOKEN_OWNER: quayadmin
BOOTSTRAP_TOKEN_EXPIRATION: 7776000
BOOTSTRAP_TOKEN_SCOPE: "org:admin repo:admin repo:create repo:read repo:write super:user user:admin user:read"

Note

For Operator deployments, omit BOOTSTRAP_TOKEN_PATH and the PROGRAMMATIC_TOKEN_K8S_* fields from the configBundleSecret. The Operator injects PROGRAMMATIC_TOKEN_K8S_SECRET, PROGRAMMATIC_TOKEN_K8S_KEY, and PROGRAMMATIC_TOKEN_PATH, and creates the <quayregistry_name>-bootstrap-token Secret, Role, and RoleBinding automatically.

Always quote BOOTSTRAP_TOKEN_SCOPE. Unquoted values that contain : can be misparsed by YAML.

Important

The bootstrap token is a high-privilege credential. Use it only to provision organizations, applications, and narrower-scoped OAuth tokens for automation. Do not use the bootstrap token for routine API operations.

For regulated environments, set BOOTSTRAP_TOKEN_EXPIRATION according to your token rotation policy and renew the token by using POST /api/v1/bootstrap/renew.

To configure filesystem-based bootstrap OAuth token provisioning in a standalone Red Hat Quay deployment, you can set FEATURE_PROGRAMMATIC_BOOTSTRAP and related fields in the config.yaml file, then restart the registry.

Prerequisites

  • You have a standalone Red Hat Quay deployment with at least one superuser account created.
  • You can modify the Red Hat Quay config.yaml file.

Procedure

  1. Set the following fields in your Red Hat Quay config.yaml file:

    FEATURE_PROGRAMMATIC_BOOTSTRAP: true
    SUPER_USERS:
      - quayadmin
    BOOTSTRAP_TOKEN_OWNER: quayadmin
    BOOTSTRAP_TOKEN_EXPIRATION: 7776000
    BOOTSTRAP_TOKEN_SCOPE: "org:admin repo:admin repo:create repo:read repo:write super:user user:admin user:read"
    BOOTSTRAP_TOKEN_PATH: /datastorage/bootstrap-token.json

    Set BOOTSTRAP_TOKEN_PATH to a directory that the Red Hat Quay process can write. In containerized standalone deployments, use a mounted storage path such as /datastorage/bootstrap-token.json. Quote the BOOTSTRAP_TOKEN_SCOPE value so YAML does not misparse scopes that contain :.

  2. Restart Red Hat Quay after you update the configuration.

    Note

    If you enable FEATURE_PROGRAMMATIC_BOOTSTRAP on a deployment that is already running, you must restart Red Hat Quay so the bootstrap token is provisioned and the POST /api/v1/bootstrap/renew endpoint is registered. A full restart is required; reloading configuration without restarting does not register the bootstrap API endpoints.

  3. Verify bootstrap provisioning:

    1. Check Red Hat Quay startup logs for a Bootstrap token provisioned message.
    2. Confirm that the bootstrap token file exists at the configured storage location. For example:

      $ ls -l <BOOTSTRAP_TOKEN_PATH>

To enable filesystem-independent bootstrap OAuth token provisioning for Red Hat Quay on OpenShift Container Platform, you can add the programmatic bootstrap fields to the configBundleSecret resource. The Red Hat Quay Operator creates the bootstrap token Secret, Role, and RoleBinding, injects the Kubernetes storage fields, and restarts the Quay pods.

Important

Programmatic bootstrap token provisioning is a Tech Preview feature in Red Hat Quay 3.18. Tech Preview features are not supported with Red Hat production service-level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using Tech Preview features in production environments. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

Prerequisites

  • You have deployed a Red Hat Quay registry on OpenShift Container Platform by using the Red Hat Quay Operator.
  • You have created at least one superuser account. For more information, see Creating the first user.
  • You can edit the configBundleSecret resource that is referenced by your QuayRegistry custom resource (CR).

Procedure

  1. Retrieve the name of the configBundleSecret resource:

    $ oc get quayregistry <quayregistry_name> -n <quay_namespace> \
      -o jsonpath='{.spec.configBundleSecret}{"\n"}'

    Example output

    example-registry-config-bundle-abc12

  2. Export the current config.yaml file from the secret:

    $ oc get secret -n <quay_namespace> <config_bundle_secret_name> \
      -o jsonpath='{.data.config\.yaml}' | base64 -d > config.yaml
  3. Edit config.yaml and add the programmatic bootstrap fields. For example:

    FEATURE_PROGRAMMATIC_BOOTSTRAP: true
    SUPER_USERS:
      - quayadmin
    BOOTSTRAP_TOKEN_OWNER: quayadmin
    BOOTSTRAP_TOKEN_EXPIRATION: 7776000
    BOOTSTRAP_TOKEN_SCOPE: "org:admin repo:admin repo:create repo:read repo:write super:user user:admin user:read"
    Important
    • BOOTSTRAP_TOKEN_OWNER must be an existing superuser that is also listed under SUPER_USERS.
    • Quote the BOOTSTRAP_TOKEN_SCOPE value. Unquoted scope strings that contain : can be misparsed by YAML.
    • Do not set BOOTSTRAP_TOKEN_PATH for Operator deployments. The Operator stores the token in a Kubernetes Secret.
    • You do not need to set PROGRAMMATIC_TOKEN_K8S_SECRET, PROGRAMMATIC_TOKEN_K8S_KEY, or PROGRAMMATIC_TOKEN_K8S_NAMESPACE. The Operator injects those values and creates the Secret named <quayregistry_name>-bootstrap-token.
  4. Create a new config bundle secret that includes the updated config.yaml file:

    $ oc create secret generic <new_config_bundle_secret_name> \
      --from-file=config.yaml=./config.yaml \
      -n <quay_namespace>
  5. Update the QuayRegistry CR to reference the new secret:

    $ oc patch quayregistry <quayregistry_name> -n <quay_namespace> \
      --type=merge -p '{"spec":{"configBundleSecret":"<new_config_bundle_secret_name>"}}'

    The Operator reconciles the change, creates the <quayregistry_name>-bootstrap-token Secret with accompanying Role and RoleBinding resources, mounts the Secret into the Quay application pods, and restarts Quay-related pods.

  6. Wait for the Quay application pods to become ready:

    $ oc get pods -n <quay_namespace> -l quay-component=quay-app
  7. Verify that the Operator created the bootstrap token Secret:

    $ oc get secret <quayregistry_name>-bootstrap-token -n <quay_namespace>
  8. Read the bootstrap token from the Secret:

    $ BOOTSTRAP_TOKEN=$(oc get secret <quayregistry_name>-bootstrap-token -n <quay_namespace> \
      -o jsonpath='{.data.token\.json}' | base64 -d | jq -r '.access_token')
    Note

    Secret propagation can take up to 60 seconds after the Quay pods start. If token.json is missing, wait and retry the command.

  9. Optional. Confirm that Quay startup logs include a bootstrap provisioning message:

    $ oc logs -n <quay_namespace> deploy/<quayregistry_name>-quay-app -c quay-app \
      | grep -i 'bootstrap token'

2.4. Reading the bootstrap token

To obtain the bootstrap OAuth token after Red Hat Quay starts with programmatic bootstrap enabled, you can read the token from the configured local file or Kubernetes Secret.

Procedure

  1. For standalone or virtual machine deployments, read the token from the BOOTSTRAP_TOKEN_PATH file:

    $ BOOTSTRAP_TOKEN=$(jq -r '.access_token' /var/lib/quay/quay-machine-token.json)
    Note

    Red Hat Quay writes the bootstrap token file with 0600 permissions owned by the Red Hat Quay process user. If you cannot read the file from the host, read it from inside the Red Hat Quay container instead. For example:

    $ BOOTSTRAP_TOKEN=$(docker exec quay cat /datastorage/bootstrap-token.json | jq -r '.access_token')
  2. For Red Hat Quay on OpenShift Container Platform Operator deployments, read the token from the Operator-managed Secret. The Secret name is <quayregistry_name>-bootstrap-token:

    $ BOOTSTRAP_TOKEN=$(oc get secret <quayregistry_name>-bootstrap-token -n <quay_namespace> \
      -o jsonpath='{.data.token\.json}' | base64 -d | jq -r '.access_token')

    Example

    $ BOOTSTRAP_TOKEN=$(oc get secret example-registry-bootstrap-token -n quay-operator \
      -o jsonpath='{.data.token\.json}' | base64 -d | jq -r '.access_token')

    Note

    Secret propagation can take up to 60 seconds after renewal or initial provisioning. If the token.json key is missing, wait for the Quay application pods to finish starting and retry the command.

To provision Red Hat Quay resources without using the UI, you can use the bootstrap OAuth token as Bearer authentication for organization, application, and token API calls.

Procedure

  1. Export the bootstrap token. For example:

    $ export BOOTSTRAP_TOKEN=<bootstrap_token_value>
  2. Create an organization:

    $ curl -H "Authorization: Bearer $BOOTSTRAP_TOKEN" -X POST \
      -H "Content-Type: application/json" \
      -d '{"name": "myorg", "email": "admin@example.com"}' \
      https://<quay-server.example.com>/api/v1/organization/
  3. Create an OAuth application in the organization:

    $ curl -H "Authorization: Bearer $BOOTSTRAP_TOKEN" -X POST \
      -H "Content-Type: application/json" \
      -d '{"name": "ci-automation", "description": "CI/CD token source"}' \
      https://<quay-server.example.com>/api/v1/organization/myorg/applications
  4. Create a scoped OAuth API token for the application:

    $ curl -H "Authorization: Bearer $BOOTSTRAP_TOKEN" -X POST \
      -H "Content-Type: application/json" \
      -d '{"name": "ci-job-token", "scope": "repo:read repo:write", "expiration": 2592000}' \
      https://<quay-server.example.com>/api/v1/organization/myorg/applications/<client_id>/tokens
  5. Store the token value from the response for your automation workflow. The token secret is returned only in the create response.

To manage organization application OAuth tokens without using the UI, you can list, create, and revoke tokens through the Red Hat Quay REST API when your token has org:admin scope.

The bootstrap token includes org:admin by default. Scoped tokens that you create for automation must also include org:admin to list, create, or revoke application tokens through these endpoints.

Procedure

  1. List existing tokens for an application:

    $ curl -H "Authorization: Bearer <access_token>" -X GET \
      https://<quay-server.example.com>/api/v1/organization/myorg/applications/<client_id>/tokens
  2. Create a token with a custom expiration and scope:

    $ curl -H "Authorization: Bearer <access_token>" -X POST \
      -H "Content-Type: application/json" \
      -d '{"name": "short-lived-token", "scope": "repo:read", "expiration": 3600}' \
      https://<quay-server.example.com>/api/v1/organization/myorg/applications/<client_id>/tokens
  3. Revoke a token by UUID:

    $ curl -H "Authorization: Bearer <access_token>" -X DELETE \
      https://<quay-server.example.com>/api/v1/organization/myorg/applications/<client_id>/tokens/<token_uuid>

2.7. Renewing the bootstrap token

To keep automation running when the bootstrap OAuth token approaches expiry, you can renew it through the Red Hat Quay REST API before the previous token is invalidated.

Procedure

  1. Renew the token by using the bootstrap token as Bearer authentication:

    $ curl -H "Authorization: Bearer $BOOTSTRAP_TOKEN" -X POST \
      https://<quay-server.example.com>/api/v1/bootstrap/renew

    The following example shows a successful response:

    {"status": "rotated"}
  2. Read the new token value from BOOTSTRAP_TOKEN_PATH or the configured Kubernetes Secret. The previous bootstrap token is invalidated immediately.

    Note

    If the bootstrap token is already expired, renewal is accepted only from localhost. On Kubernetes and OpenShift Container Platform, use port forwarding to send the renewal request through the local ingress path.

2.8. Revoking the bootstrap token

You can revoke the Red Hat Quay bootstrap OAuth token by disabling FEATURE_PROGRAMMATIC_BOOTSTRAP and restarting the registry. Red Hat Quay does not provide a separate API endpoint for instant revocation.

To revoke the bootstrap token, set FEATURE_PROGRAMMATIC_BOOTSTRAP: false and restart Red Hat Quay. Red Hat Quay deletes bootstrap-managed applications and tokens during startup.

Apply these practices when you use the Red Hat Quay bootstrap OAuth token so that automation remains limited to provisioning and uses narrower-scoped tokens for day-to-day work.

  • Use the bootstrap token only for initial provisioning and token minting. Create narrower-scoped OAuth tokens for CI/CD and day-2 automation.
  • Set BOOTSTRAP_TOKEN_EXPIRATION according to your security policy. The default is 60 minutes.
  • On standalone deployments, the bootstrap token file is written with 0600 permissions. Restrict access to the directory that contains the token file.
  • On Kubernetes and OpenShift Container Platform, store the bootstrap token in a dedicated Secret with scoped RBAC.
  • Schedule bootstrap token renewal by using POST /api/v1/bootstrap/renew before expiry.
  • Monitor Red Hat Quay action logs for bootstrap and OAuth token life cycle events.

2.10. Troubleshooting programmatic bootstrap

Use these checks when programmatic bootstrap token provisioning fails in Red Hat Quay, including missing token files, authorization errors, and renewal failures.

If the token file or Secret is empty after startup:

  • Verify that FEATURE_PROGRAMMATIC_BOOTSTRAP is true.
  • Verify that BOOTSTRAP_TOKEN_OWNER is set and listed in SUPER_USERS.
  • Verify that the bootstrap token owner exists in the Red Hat Quay database.
  • Check Red Hat Quay startup logs for bootstrap provisioning errors.
  • If the bootstrap token file or Secret is still missing after the first restart, restart Red Hat Quay again or run python3 /quay-registry/boot.py inside the Red Hat Quay container after confirming BOOTSTRAP_TOKEN_OWNER exists in the database.
  • On Red Hat Quay on OpenShift Container Platform, confirm that the Operator created the <quayregistry_name>-bootstrap-token Secret, Role, and RoleBinding, and that Quay application pods have rolled out with the updated configBundleSecret. An empty Secret before the pods restart is expected; the Quay process writes token.json after startup.
  • Confirm that BOOTSTRAP_TOKEN_SCOPE is a quoted YAML string. Unquoted scope values that contain : can be misparsed.

If you receive 403 Forbidden when using the bootstrap token:

  • Confirm that the token has not expired.
  • Confirm that bootstrap provisioning was not disabled and the token revoked.
  • Confirm that the target API endpoint is authorized by the bootstrap token scope.

If renewal returns 401 Unauthorized:

  • If the token is expired, send the renewal request from localhost or through a port-forwarded local ingress path.
  • Confirm that you are passing the bootstrap token value, not a different OAuth token.

If rate limiting returns 429 Too Many Requests:

  • Bootstrap and token management endpoints are subject to existing rate limiting when FEATURE_RATE_LIMITS is enabled. Adjust request frequency or review your rate limit configuration.
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat Documentation

Legal Notice

Theme

© 2026 Red Hat
Back to top