Get started with the Red Hat Quay API

Learn how OAuth 2.0 tokens work, enable the Red Hat Quay API, and use API endpoints, Swagger, and automation workflows. Before you call authenticated endpoints, create an OAuth 2 access token; see "Manage OAuth access tokens for the Red Hat Quay API".

Introduction to Project Quay OAuth 2.0 tokens

OAuth 2.0 tokens provide secure, standards-based access to the Project Quay API. You can use OAuth 2 access tokens, robot account tokens, and OCI referrers access tokens to authenticate API operations.

Compared to more traditional API tokens, Project Quay OAuth 2 tokens offer the following enhancements:

  • Standards-based security that adheres to the OAuth 2.0 protocol.

  • Revocable access by deleting the application in which the OAuth 2 token exists.

  • Fine-grained access control so that Project Quay administrators can assign specific permissions to tokens.

  • Delegated access so that third-party applications and services can act on behalf of a user.

  • Compatibility with other services, platforms, and integrations.

Project Quay primarily supports two types of tokens: OAuth 2 access tokens and robot account tokens. A third token type, an OCI referrers access token, that is required to list OCI referrers of a manifest under a repository, is also available when warranted.

You can manage organization OAuth 2 access tokens from the API Access Tokens page of an OAuth application. You can create named tokens with optional expiration, review metadata such as scopes and last-used time, and revoke individual tokens without deleting the parent application.

Additional resources

Using the Project Quay API

To invoke Project Quay API endpoints from the CLI, you can pass an OAuth 2 access token in a curl request. You can use GET, PUT, POST, or DELETE methods against the documented endpoints.

After you have created an application and generated an OAuth 2 access token with the desired settings, you can pass in the access token to GET, PUT, POST, or DELETE settings by using the API from the CLI. Generally, a Project Quay API command looks similar to the following example:

$ curl -X GET -H "Authorization: Bearer <your_access_token>" \
    https://<quay-server.example.com>/api/v1/<example>/<endpoint>/

where:

<your_access_token>

Specifies the OAuth 2 access token that was generated through the Project Quay UI.

https://<quay-server.example.com>/api/v1/<example>/<endpoint>/

Specifies your Project Quay deployment and the desired API endpoint.

All Project Quay APIs are documented in the Application Programming Interface (API) chapter. Understanding how they are documented is crucial to successful invocation. Take, for example, the following entry for the createAppToken API endpoint:

*createAppToken*
Create a new app specific token for user.

*POST /api/v1/user/apptoken*

**Authorizations: **oauth2_implicit (**user:admin**)

 Request body schema (application/json)

*Path parameters*

Name: **title**
Description: Friendly name to help identify the token.
Schema: string

*Responses*

|HTTP Code|Description             |Schema
|201      |Successful creation     |
|400      |Bad Request             |&lt;&lt;_apierror,ApiError&gt;&gt;
|401      |Session required        |&lt;&lt;_apierror,ApiError&gt;&gt;
|403      |Unauthorized access     |&lt;&lt;_apierror,ApiError&gt;&gt;
|404      |Not found               |&lt;&lt;_apierror,ApiError&gt;&gt;
|===

where:

createAppToken

Specifies the name of the API endpoint.

Create a new app specific token for user.

Specifies a brief description of the API endpoint.

POST /api/v1/user/apptoken

Specifies the API endpoint used for invocation.

Authorizations

Specifies the authorizations required to use the API endpoint.

Path parameters

Specifies the available paths to be used with the API endpoint. In this example, title is the only path to be used with the POST /api/v1/user/apptoken endpoint.

Responses

Specifies the API responses for this endpoint.

Enabling browser-based API calls in Project Quay

To use Project Quay API access from a browser extension or Swagger UI, you can disable BROWSER_API_CALLS_XHR_ONLY in your config.yaml file.

By default, Project Quay accepts curl requests from the command line. However, if you want to enable API access from a browser extension such as Postman, or a browser interface such as Swagger, you must disable BROWSER_API_CALLS_XHR_ONLY in your config.yaml file.

Procedure
  1. In your Project Quay config.yaml file, set BROWSER_API_CALLS_XHR_ONLY to false. For example:

    # ...
    BROWSER_API_CALLS_XHR_ONLY: false
    # ...
  2. Restart your Project Quay deployment.

Accessing Project Quay Swagger UI

To explore and test Project Quay API endpoints interactively, you can run the Swagger UI container against your registry API discovery endpoint.

Project Quay administrators and users can interact with the API by using the Swagger UI, an interactive web interface that compiles executable commands. The Swagger UI can be launched as a container that points to your Project Quay instance’s API discovery endpoint (/api/v1/discovery). After deploying the container, you can access the Swagger UI, which loads the OpenAPI specification for Project Quay from the specified URL. Project Quay administrators and users can explore the available endpoints and their structure.

Prerequisites
  • You have set BROWSER_API_CALLS_XHR_ONLY: false in your config.yaml file.

Procedure
  1. Enter the following command to deploy the Swagger UI container, pointing the URL to your Project Quay API discovery endpoint. For example:

    $ podman run -p 8080:8080 -e SWAGGER_JSON_URL=<quay-server.example.com> docker.swagger.io/swaggerapi/swagger-ui
    Example output
    ---
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    20-envsubst-on-templates.sh: Running envsubst on /etc/nginx/templates/default.conf.template to /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/40-swagger-ui.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    ---
  2. Navigate to the localhost URL. In this example, the URL is http://localhost:8080/.

  3. Use the Swagger UI to test various API endpoints. For example, to create a new token for a user, you can click the POST /api/v1/user/apptoken endpoint → Try it outExecute to generate an example curl command.

    Note

    Currently, server responses cannot be generated. This is because the Swagger UI is not configured to accept bearer tokens. As a result, the following error is returned for each command: {"error": "CSRF token was invalid or missing."}. As a workaround, you can copy this command into your terminal and manually add your bearer token, for example, -H 'Authorization: Bearer <bearer_token>'.

Automating Project Quay processes by using the API

To automate repetitive Project Quay tasks such as repository management or image pruning, you can call the API from scripts and schedule them with cron.

With the API, Project Quay administrators and users with access to the API can automate repetitive tasks such as repository management or image pruning.

The following example shows you how you might use a Python script and a cron job to automate the deletion of OAuth 2 applications except the administrator’s token. This might be useful if you want to ensure an application associated with an OAuth 2 access token is cycled after a certain period of time.

Prerequisites
  • You have access to the Project Quay API, which entails having already created an OAuth 2 access token.

  • You have installed the Python requests library.

  • You have enabled cron jobs on your machine.

  • You have created several organization applications, including one that you do not want to delete.

Procedure
  1. Create a Python script that executes an API command. The following example deletes organization applications by using the DELETE /api/v1/organization/{orgname}/applications/{client_id} API endpoint.

    Create the following example.py file:

    import requests
    
    # Hard-coded values
    API_BASE_URL = "http://<quay-server.example.com>/api/v1"
    ACCESS_TOKEN = "<access_token>"
    ORG_NAME = "<organization_name>"
    
    def get_all_organization_applications():
        url = f"{API_BASE_URL}/organization/{ORG_NAME}/applications"
        headers = {
            "Authorization": f"Bearer {ACCESS_TOKEN}"
        }
    
        response = requests.get(url, headers=headers)
    
        if response.status_code == 200:
            try:
                applications = response.json()
                # Print the raw response for debugging
                print("Raw response:", applications)
    
                # Adjust parsing logic based on the response structure
                if isinstance(applications, dict) and 'applications' in applications:
                    applications = applications['applications']
    
                if isinstance(applications, list):
                    print("Organization applications retrieved successfully:")
                    for app in applications:
                        # Updated key from 'title' to 'name'
                        print(f"Name: {app['name']}, Client ID: {app['client_id']}")
                    return applications
                else:
                    print("Unexpected response format.")
                    return []
            except requests.exceptions.JSONDecodeError:
                print("Error decoding JSON response:", response.text)
                return []
        else:
            print(f"Failed to retrieve applications. Status code: {response.status_code}, Response: {response.text}")
            return []
    
    def delete_organization_application(client_id):
        url = f"{API_BASE_URL}/organization/{ORG_NAME}/applications/{client_id}"
        headers = {
            "Authorization": f"Bearer {ACCESS_TOKEN}"
        }
    
        response = requests.delete(url, headers=headers)
    
        if response.status_code == 204:
            print(f"Application {client_id} deleted successfully.")
        else:
            print(f"Failed to delete application {client_id}. Status code: {response.status_code}, Response: {response.text}")
    
    def main():
        applications = get_all_organization_applications()
        for app in applications:
            if app['name'] != "<admin_token_app>":  # Skip the "admin-token-app"
                delete_organization_application(app['client_id'])
            else:
                print(f"Skipping deletion of application: {app['name']}")
    
    # Execute the main function
    main()

    where:

    import requests

    Specifies that the requests library is included in your Python code.

    API_BASE_URL

    Specifies the URL of your registry appended with /api/v1.

    ACCESS_TOKEN

    Specifies your OAuth 2 access token.

    ORG_NAME

    Specifies the organization that holds the application.

    "<admin_token_app>"

    Specifies the name of the application token to remain.

  2. Save the script as prune_applications.py.

  3. Create a cron job that automatically runs the script:

    1. Open the crontab editor by running the following command:

      $ crontab -e
    2. In the editor, add the cron job for running the script. The following example runs the script once per month:

      0 0 1 * * sudo python /path/to/prune_images.py >> /var/log/prune_images.log 2>&1

Discovering Project Quay API endpoints

To list available Project Quay API endpoints in Swagger format, you can call the discovery endpoint with an OAuth 2 access token.

Prerequisites
  • You have created an OAuth 2 access token.

Procedure
  • Enter the following GET /api/v1/discovery command to list all of the API endpoints available in the Swagger API format:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/discovery?query=true" \
        -H "Authorization: Bearer <access_token>"
    Example output
    ---
    : "Manage the tags of a repository."}, {"name": "team", "description": "Create, list and manage an organization's teams."}, {"name": "trigger", "description": "Create, list and manage build triggers."}, {"name": "user", "description": "Manage the current user."}, {"name": "userfiles", "description": ""}]}
    ---

Obtaining Project Quay API error details

To retrieve details for a Project Quay API error type, you can call the error endpoint with an OAuth 2 access token and an error code.

Prerequisites
  • You have created an OAuth 2 access token.

Procedure
  • Obtain error details of the API by entering the GET /api/v1/error/{error_type} endpoint. Note that you must include one of the following error codes:

    HTTP Code Description

    200

    Successful invocation

    400

    Bad Request

    401

    Session required

    403

    Unauthorized access

    404

    Not found

    $ curl -X GET "https://<quay-server.example.com>/api/v1/error/<error_type>" \
        -H "Authorization: Bearer <access_token>"
    Example output
    curl: (7) Failed to connect to quay-server.example.com port 443 after 0 ms: Couldn't connect to server

Manage OAuth access tokens for the Red Hat Quay API

Review OAuth 2 access token scopes and security, then create, reassign, revoke, and rotate organization OAuth 2 access tokens. After you have an OAuth 2 access token, you can create user application tokens for Docker, Podman, and other clients.

About OAuth 2 access tokens

OAuth 2 access tokens authenticate users to the Project Quay API for applications that require user identity verification. You create a token for an organization OAuth application and select scopes that authorize API actions.

Note

Although OAuth 2 tokens authorize actions on API endpoints based on the scopes that you define for the token, Project Quay role-based access control (RBAC) still governs access to the resources. You can create actions on a resource, for example a repository, when you have the proper role (Admin or Creator) for that namespace. This is true even if the API token was granted the repo:admin scope.

You can create OAuth 2 access tokens by using the Project Quay UI or by using the organization application token API.

When you create an OAuth 2 token, you can select the following options:

  • Name. A user-defined identifier for the token.

  • Expiration. A lifetime for the token. Use short expirations for scripts and CI systems when practical. Use no expiration only for controlled bootstrap cases.

  • Scopes, which can include the following permissions:

    • Administer Organization. Administration of organizations, including creating robots, creating teams, adjusting team membership, and changing billing settings.

    • Administer Repositories. Administrator access to all repositories to which the granting user has access.

    • Create Repositories. Creation of repositories in namespaces where the granting user can create repositories.

    • View all visible repositories. Viewing and pulling all repositories visible to the granting user.

    • Read/Write to any accessible repositories. Viewing, pushing, and pulling to repositories where the granting user has write access.

    • Super User Access. Administration of the installation, including managing users and organizations from the superuser panel.

    • Administer User. Administration of your account, including creating robots and granting them repository permissions.

    • Read User Information. Reading user information such as username and email address.

The API Access Tokens page can show additional columns such as Created By, Expires, and Last Used so that you can audit tokens without deleting the parent application.

Important

The token secret is shown only when the token is created. Store it securely. Do not share token secrets through insecure channels.

OAuth 2 access tokens are passed as a Bearer token in the Authorization header of an API call. The API is available from the /api/v1 endpoint of your Project Quay host. For example, https://<quay-server.example.com>/api/v1. You can connect to endpoints through your browser to GET, POST, DELETE, and PUT Project Quay settings by enabling the Swagger UI. Applications that make API calls and use OAuth tokens can access the API, which sends and receives data as JSON.

Organization application OAuth API tokens created through the UI support various expiration values, from 7 days to 10 years. Tokens created by using the organization application token API support custom expiration values in seconds. You can revoke tokens individually by using the API or by deleting the application in which they were created. Deleting an application revokes all tokens created within that application.

Token distributors should be mindful of the permissions that they grant when generating a token on behalf of a user, and should have absolute trust in a user before granting such permissions as Administer organization, Super User Access, and Administer User. Additionally, the access token is only revealed at the time of creation; they cannot be listed from the CLI, nor can they be found on the Project Quay UI. If an access token is lost or forgotten, a new token must be created; a token cannot be recovered.

In practice, Project Quay administrators can create a new OAuth application on the OAuth Applications page of their organization each time they want to create a new OAuth token for a user. This ensures that a single application is not responsible for all OAuth tokens. As a result, if a user’s token is compromised, the administrator can delete the application of the compromised token without disrupting other users whose tokens might be part of the same application.

Older tokens that you created with the previous Generate Token workflow continue to work. In the API Access Tokens list, legacy tokens might appear with a name such as Legacy Token. You can leave them in place, or replace them with named tokens that have explicit expiration policies and then revoke the legacy token.

Note

Deleting an OAuth application still deletes all tokens that belong to that application. Prefer revoking an individual token from the API Access Tokens page when you only need to invalidate one credential.

Creating an OAuth 2 access token

To create an OAuth 2 access token for Project Quay API calls, you can generate a named token from an organization OAuth application in the UI.

Prerequisites
  • You have logged in to Project Quay as an administrator.

  • You have created an organization.

Procedure
  1. On the Project Quay UI, select your organization.

  2. In the navigation pane, click OAuth Applications.

  3. Create an application if you do not already have one:

    1. Click Create OAuth Application.

    2. Enter an application name and any required application details, such as homepage URL, description, avatar e-mail, and redirect/callback URL.

    3. Click Create application.

  4. Click the name of your OAuth application.

  5. Click API Access Tokens.

  6. Click Generate New Token.

  7. Configure the token:

    1. Enter a Token name.

    2. Set an expiration period, such as 10 years.

    3. Optional: Click Assign another user to assign this OAuth token to another user. When prompted, select the desired user.

    4. Select the permissions, or scopes, for the token. For example:

      1. Administer Organization. This application can administer your organizations, including creating robots, creating teams, adjusting team membership, and changing billing settings. Grant this permission only when you have absolute trust in the requesting application.

      2. Administer Repositories. This application has administrator access to all repositories to which the granting user has access.

      3. Create Repositories. This application can create repositories in all namespaces where the granting user can create repositories.

      4. View all visible repositories. This application can view and pull all repositories visible to the granting user.

      5. Read/Write to any accessible repositories. This application can view, push, and pull to all repositories to which the granting user has write access.

      6. Super User Access. This application can administer your installation, including managing users, managing organizations, and other features found in the superuser panel. Grant this permission only when you have absolute trust in the requesting application.

      7. Administer User. This application can administer your account, including creating robots and granting them permissions to your repositories. Grant this permission only when you have absolute trust in the requesting application.

      8. Read User Information. This application can read user information such as username and email address.

  8. Click Generate token.

  9. Review the requested permissions, then click Authorize Application. Confirm the authorization when prompted.

    Important

    Assign only the scopes that the token holder needs. Treat Administer Organization, Super User Access, and Administer User as high-trust permissions.

  10. Copy and store the access token secret.

    Important

    This is the only opportunity to copy the token secret. Project Quay does not show the full secret again after you leave the page.

Verification
  1. Confirm that the new token appears on the API Access Tokens page for the application. The list can include the token name, creator, scopes, expiration, and last-used information when those columns are available.

  2. Optional. Call an API endpoint with the token to confirm that it works. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/user/" \
         -H "Authorization: Bearer <access_token>"

Managing a user application by using the API

To create, list, or delete a user application token without sharing your password, you can use the Project Quay API. User application tokens work like encrypted username and password credentials for Docker, Podman, or other clients.

Project Quay users can create, list information about, and delete a user application that can be used as an alternative to using your password for Docker, Podman, or other service providers. User application tokens work like your username and password, but are encrypted and do not provide any information to third parties regarding who is accessing Project Quay.

Note

After creation by using the CLI, the user application token is listed under User Settings of the Project Quay UI. Note that this differs from an application token that is created under user settings, and should be considered a different application entirely.

Prerequisites
  • You have created an OAuth 2 access token.

Procedure
  • Create a user application by entering the POST /api/v1/user/apptoken API call:

    $ curl -X POST \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{
        "title": "MyAppToken"
      }' \
      "http://quay-server.example.com/api/v1/user/apptoken"
    Example output
    {"token": {"uuid": "6b5aa827-cee5-4fbe-a434-4b7b8a245ca7", "title": "MyAppToken", "last_accessed": null, "created": "Wed, 08 Jan 2025 19:32:48 -0000", "expiration": null, "token_code": "string"}}
  • You can obtain information about your application, including when the application expires, by using the GET /api/v1/user/apptoken command. For example:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "http://quay-server.example.com/api/v1/user/apptoken"
    Example output
    {"tokens": [{"uuid": "6b5aa827-cee5-4fbe-a434-4b7b8a245ca7", "title": "MyAppToken", "last_accessed": null, "created": "Wed, 08 Jan 2025 19:32:48 -0000", "expiration": null}], "only_expiring": null}
  • You can obtain information about a specific user application by entering the GET /api/v1/user/apptoken/{token_uuid} command:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "http://quay-server.example.com/api/v1/user/apptoken/<token_uuid>"
    Example output
    {"token": {"uuid": "6b5aa827-cee5-4fbe-a434-4b7b8a245ca7", "title": "MyAppToken", "last_accessed": null, "created": "Wed, 08 Jan 2025 19:32:48 -0000", "expiration": null, "token_code": "string"}}
  • You can delete or revoke a user application token by using the DELETE /api/v1/user/apptoken/{token_uuid} endpoint:

    $ curl -X DELETE \
      -H "Authorization: Bearer <access_token>" \
      "http://quay-server.example.com/api/v1/user/apptoken/<token_uuid>"

    This command does not return output in the CLI. You can return a list of tokens by entering one of the aforementioned commands.

Reassigning an OAuth access token

To keep audit logs accurate when another user needs an OAuth API token, you can reassign token creation to that user from an organization OAuth application.

Organization administrators can assign OAuth API tokens to be created by other users with specific permissions. Audit logs then reflect the user who uses the token, even when that user does not have organization administrative permissions to create an OAuth API token.

Note

This procedure works only on the current Project Quay UI. The Project Quay v2 UI does not currently support this procedure.

Prerequisites
  • You are logged in as a user with organization administrative privileges, which allows you to assign an OAuth API token.

    Note

    OAuth API tokens are used for authentication and not authorization. For example, the user that you are assigning the OAuth token to must have the Admin team role to use administrative API endpoints.

Procedure
  1. Optional. If not already, update your Project Quay config.yaml file to include the FEATURE_ASSIGN_OAUTH_TOKEN: true field:

    # ...
    FEATURE_ASSIGN_OAUTH_TOKEN: true
    # ...
  2. Optional. Restart your Project Quay registry.

  3. Log in to your Project Quay registry as an organization administrator.

  4. Click the name of the organization in which you created the OAuth token.

  5. In the navigation pane, click OAuth Applications.

  6. Click the proper application name.

  7. In the navigation pane, click API Access Tokens.

  8. Click Generate New Token.

  9. Click Assign another user and enter the name of the user who takes over the OAuth token.

  10. Check the boxes for the desired permissions that you want the new user to have. For example, if you only want the new user to be able to create repositories, click Create Repositories.

    Important

    The team role within an organization defines permission control and must be configured regardless of the options selected here. For example, the user that you are assigning the OAuth token to must have the Admin team role to use administrative API endpoints.

    Solely checking the Super User Access box does not actually grant the user this permission. Superusers must be configured by using the config.yaml file and the box must be checked here.

  11. Click Assign token. A popup box appears that confirms authorization with the following message and shows you the approved permissions:

    This will prompt user <username> to generate a token with the following permissions:
    repo:create
  12. Click Assign token in the popup box. You are redirected to a new page that displays the following message:

    Token assigned successfully
Verification
  1. After reassigning an OAuth token, the assigned user must accept the token to receive the bearer token, which is required to use API endpoints. Ask the assigned user to log in to the Project Quay registry.

  2. After the assigned user has logged in, ask them to click their username under Users and Organizations.

  3. In the navigation pane, ask them to click External Logins And Applications.

  4. Under Authorized Applications, ask them to confirm the application by clicking Authorize Application. They are directed to a new page where they must reconfirm by clicking Authorize Application.

  5. They are redirected to a new page that reveals their bearer token. Ask them to save this bearer token, because it cannot be viewed again.

Revoking an OAuth 2 access token

To invalidate a compromised or unused OAuth 2 access token, you can revoke the token from the organization OAuth application in the Project Quay UI.

Because OAuth 2 access tokens are created through the OAuth application, they cannot be rotated or renewed. If a token is compromised, revoke it through the Project Quay UI.

Prerequisites
  • You have created an OAuth 2 access token.

  • You have permission to manage the OAuth application that owns the token.

Procedure
  1. On the Project Quay UI, click the name of the organization that hosts the application.

  2. In the navigation pane, click OAuth Applications.

  3. Click the application name that holds the OAuth 2 token that you want to revoke.

  4. Click API Access Tokens.

  5. Click the menu kebab of the appropriate token and then click Revoke. Confirm that you want to revoke the token by clicking Revoke token.

Verification
  1. Confirm that the token no longer appears as an active token on the API Access Tokens page.

Rotating a legacy OAuth 2 access token

To replace a legacy long-lived OAuth 2 access token, you can create a named token with an explicit expiration policy and then revoke the legacy token.

Existing legacy tokens continue to work for at least 10 years until you revoke them.

Prerequisites
  • You have an organization OAuth application that already has a legacy token.

  • You can update any CI system, script, or client that currently uses the legacy token.

Procedure
  1. On the Project Quay UI, click OrganizationOAuth Applications.

  2. Click the application name.

  3. Click API Access Tokens.

  4. Identify the legacy token to replace. Legacy tokens do not have a user-defined name, do not show a creation date, and have an expiration date of 10 years from the date of creation.

  5. Click Generate New Token.

  6. Configure a replacement token:

    1. Enter a Token name.

    2. Set an expiration appropriate for the workload, for example 7 days or 10 years.

    3. Select the scopes required by the client.

  7. Click Generate Token, then click Authorize Application and confirm the authorization.

  8. Copy the new token secret and store it securely.

  9. Update the CI system, script, or client configuration to use the new token.

  10. Verify that the client works with the new token.

  11. Return to the OAuth Applications page and revoke the legacy token:

    1. Click the application name that owns the legacy token.

    2. Click the menu kebab icon for the legacy token.

    3. Click Revoke. Confirm that you want to revoke the token by clicking Revoke token.

Manage robot account tokens for the Red Hat Quay API

Create and regenerate robot account tokens for CI/CD pull and push access without interactive user authentication.

Robot account tokens

Robot account tokens are persistent password-type credentials for Docker v2 registry access in Project Quay. You can use them for automation and continuous integration without interactive user authentication.

Robot account tokens are password-type credentials used to access a Project Quay registry by using normal Docker v2 endpoints. The UI labels these credentials as tokens because the password itself is encrypted.

By default, Project Quay robot account tokens do not expire and do not require user interaction, which makes robot accounts ideal for non-interactive use cases.

Robot account tokens are automatically generated at the time of a robot’s creation and are not user-specific; they are connected to the user and organization namespace where they are created. For example, a robot named project_tools+<robot_name> belongs to the project_tools namespace.

Robot account tokens provide access without needing a user’s personal credentials. How the robot account is configured, for example, with one of READ, WRITE, or ADMIN permissions, ultimately defines the actions that the robot account can take.

Because robot account tokens are persistent and do not expire by default, they are ideal for automated workflows that require consistent access to Project Quay without manual renewal. Despite this, you can regenerate robot account tokens by using the UI or by using the proper API endpoint from the CLI. To enhance the security of your Project Quay deployment, administrators should regularly refresh robot account tokens. With the keyless authentication with robot accounts feature, you can exchange robot account tokens for external OIDC tokens so that they last only one hour, which enhances the security of your registry.

When a namespace is deleted, or when the robot account itself is deleted, the tokens are garbage collected when the collector is scheduled to run.

Regenerating a robot account token by using the Project Quay UI

To replace a robot account credential from the Project Quay UI, you can regenerate the robot account token for an organization robot account.

Prerequisites
  • You have logged into Project Quay.

Procedure
  1. Click the name of an organization.

  2. In the navigation pane, click Robot accounts.

  3. Click the name of your robot account, for example, testorg3+test.

  4. Click Regenerate token in the popup box.

Regenerating a robot account token by using the Project Quay API

To replace a compromised or outdated robot account credential, you can regenerate a robot account token by using the Project Quay API for organization or user robots.

Prerequisites
  • You have created an OAuth access token.

Procedure
  • Enter the following command to regenerate a robot account token for an organization by using the POST /api/v1/organization/{orgname}/robots/{robot_shortname}/regenerate endpoint:

    $ curl -X POST \
      -H "Authorization: Bearer <bearer_token>" \
      "<quay-server.example.com>/api/v1/organization/<orgname>/robots/<robot_shortname>/regenerate"
    Example output
    {"name": "test-org+test", "created": "Fri, 10 May 2024 17:46:02 -0000", "last_accessed": null, "description": "", "token": "<example_secret>"}
  • Enter the following command to regenerate a robot account token for the current user by using the POST /api/v1/user/robots/{robot_shortname}/regenerate endpoint:

    $ curl -X POST \
      -H "Authorization: Bearer <bearer_token>" \
      "<quay-server.example.com>/api/v1/user/robots/<robot_shortname>/regenerate"
    Example output
    {"name": "quayadmin+test", "created": "Fri, 10 May 2024 14:12:11 -0000", "last_accessed": null, "description": "", "token": "<example_secret>"}

Manage OCI referrers OAuth access tokens for the Red Hat Quay API

Create OCI referrers OAuth access tokens to list OCI referrers of a manifest under a repository by using the Project Quay v2/auth endpoint.

OCI referrers OAuth access token

An OCI referrers OAuth access token lists OCI referrers of a manifest under a repository in Project Quay. You obtain the token through basic HTTP authentication against the v2/auth endpoint.

In some cases, depending on the features that your Project Quay deployment is configured to use, you might need an OCI referrers OAuth access token. OCI referrers OAuth access tokens list OCI referrers of a manifest under a repository, and use a curl command to make a GET request to the Project Quay v2/auth endpoint.

You obtain these tokens by using basic HTTP authentication, wherein the user provides a username and password encoded in Base64 to authenticate directly with the v2/auth API endpoint. As such, they are based directly on the user’s credentials and do not follow the same detailed authorization flow as OAuth 2, but still allow a user to authorize API requests.

OCI referrers OAuth access tokens do not offer scope-based permissions and do not expire. They are solely used to list OCI referrers of a manifest under a repository.

Creating an OCI referrers OAuth access token

To list OCI referrers of a manifest under a repository, you can create an OCI referrers OAuth access token by using basic authentication against the Project Quay v2/auth endpoint.

Procedure
  1. Update your config.yaml file to include the FEATURE_REFERRERS_API: true field. For example:

    # ...
    FEATURE_REFERRERS_API: true
    # ...
  2. Enter the following command to Base64 encode your credentials:

    $ echo -n '<username>:<password>' | base64
    Example output
    abcdeWFkbWluOjE5ODlraWROZXQxIQ==
  3. Enter the following command to use the Base64-encoded string and modify the URL endpoint to your Project Quay server:

    $ curl --location '<quay-server.example.com>/v2/auth?service=<quay-server.example.com>&scope=repository:quay/listocireferrs:pull,push' --header 'Authorization: Basic <base64_username:password_encode_token>' -k | jq
    Example output
    {
      "token": "<example_secret>"
    }

Automate organization and quota operations through the Red Hat Quay API

Automate organization management, quota limits, mirroring, and global messages by using the Red Hat Quay API. Organization procedures cover contact email, members, applications, and proxy cache configuration.

Managing current user options by using the Project Quay API

To retrieve account information or star and unstar repositories in Project Quay, you can use the user API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the GET /api/v1/user/ endpoint to get user information for the authenticated user.

    $ curl -X GET "https://quay-server.example.com/api/v1/user/" \
      -H "Authorization: Bearer <your_access_token>"
    Example output
    {"anonymous": false, "username": "quayadmin", "avatar": {"name": "quayadmin", "hash": "6d640d802fe23b93779b987c187a4b7a4d8fbcbd4febe7009bdff58d84498fba", "color": "#f7b6d2", "kind": "user"}, "can_create_repo": true, "is_me": true, "verified": true, "email": "test@gmil.com", "logins": [], "invoice_email": false, "invoice_email_address": null, "preferred_namespace": false, "tag_expiration_s": 1209600, "prompts": [], "company": null, "family_name": null, "given_name": null, "location": null, "is_free_account": true, "has_password_set": true, "quotas": [{"id": 4, "limit_bytes": 2199023255552, "limits": [{"id": 3, "type": "Reject", "limit_percent": 100}]}], "quota_report": {"quota_bytes": 2280675, "configured_quota": 2199023255552, "running_backfill": "complete", "backfill_status": "complete"}, "organizations": [{"name": "test", "avatar": {"name": "test", "hash": "a15d479002b20f211568fd4419e76686d2b88a4980a5b4c4bc10420776c5f6fe", "color": "#aec7e8", "kind": "org"}, "can_create_repo": true, "public": false, "is_org_admin": true, "preferred_namespace": false}, {"name": "sample", "avatar": {"name": "sample", "hash": "ba560c68f1d26e8c6b911ac9b5d10d513e7e43e576cc2baece1b8a46f36a29a5", "color": "#b5cf6b", "kind": "org"}, "can_create_repo": true, "public": false, "is_org_admin": true, "preferred_namespace": false}], "super_user": true}
  2. Use the GET /api/v1/users/{username} endpoint to get user information for the specified user.

    $ curl -X GET "https://quay-server.example.com/api/v1/users/example_user" \
      -H "Authorization: Bearer <your_access_token>"
    Example output
    {"anonymous": false, "username": "testuser", "avatar": {"name": "testuser", "hash": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a", "color": "#6b6ecf", "kind": "user"}, "super_user": false}
  3. Use the POST /api/v1/user/starred endpoint to star a repository:

    $ curl -X POST "https://quay-server.example.com/api/v1/user/starred" \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json" \
      -d '{
            "namespace": "<namespace>",
            "repository": "<repository_name>"
          }'
    Example output
    {"namespace": "test", "repository": "testrepo"}
  4. Use the GET /api/v1/user/starred endpoint to list all starred repositories:

    $ curl -X GET "https://quay-server.example.com/api/v1/user/starred?next_page=<next_page_token>" \
      -H "Authorization: Bearer <your_access_token>"
    Example output
    {"repositories": [{"namespace": "test", "name": "testrepo", "description": "This repository is now under maintenance.", "is_public": true}]}
  5. Use the DELETE /api/v1/user/starred/{repository} endpoint to delete a star from a repository:

    $ curl -X DELETE "https://quay-server.example.com/api/v1/user/starred/namespace/repository-name" \
      -H "Authorization: Bearer <your_access_token>"

    This command does not return output in the CLI.

Managing global messages by using the API

To create, list, or delete global messages in Project Quay, you can use the messages API endpoints with an OAuth 2 access token.

Prerequisites
  • You have created an OAuth 2 access token.

Procedure
  1. Create a message by using the POST /api/v1/message endpoint:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/messages" \
        -H "Authorization: Bearer <access_token>" \
        -H "Content-Type: application/json" \
        -d '{
            "message": {
                "content": "Hi",
                "media_type": "text/plain",
                "severity": "info"
            }
        }'

    This command does not return output.

  2. Use the GET /api/v1/messages command to return the list of global messages:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/messages" \
        -H "Authorization: Bearer <access_token>"
    Example output
    {"messages": [{"uuid": "ecababd4-3451-4458-b5db-801684137444", "content": "Hi", "severity": "info", "media_type": "text/plain"}]}
  3. Delete the global message by using the DELETE /api/v1/message/{uuid} endpoint:

    $ curl -X DELETE "https://<quay-server.example.com>/api/v1/message/<uuid>" \
        -H "Authorization: Bearer <access_token>"

    This command does not return output.

Using the API to mirror a repository

To mirror an external repository into Project Quay, you can create and manage a repository mirror configuration through the API. You can also sync, cancel, or update the configuration.

Prerequisites
  • You have set FEATURE_REPO_MIRROR: true in your config.yaml file.

Procedure
  • Create a new repository mirror configuration by using the POST /api/v1/repository/{repository}/mirror endpoint:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/repository/<namespace>/<repo>/mirror" \
        -H "Authorization: Bearer <access_token>" \
        -H "Content-Type: application/json" \
        -d '{
            "is_enabled": <is_enabled>,
            "external_reference": "<external_reference>",
            "external_registry_username": "<external_registry_username>",
            "external_registry_password": "<external_registry_password>",
            "sync_start_date": "<sync_start_date>",
            "sync_interval": <sync_interval>,
            "robot_username": "<robot_username>",
            "skopeo_timeout_interval": 600,
            "root_rule": {
                "rule": "<rule>",
                "rule_type": "<rule_type>"
            }
        }'
  • Return information about the mirror configuration by using the GET /api/v1/repository/{repository}/mirror endpoint:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/repository/<namespace>/<repo>/mirror" \
         -H "Authorization: Bearer <access_token>"
    Example output
    {"is_enabled": true, "mirror_type": "PULL", "external_reference": "https://quay.io/repository/argoproj/argocd", "external_registry_username": null, "external_registry_config": {}, "sync_interval": 86400, "sync_start_date": "2025-01-15T12:00:00Z", "sync_expiration_date": null, "sync_retries_remaining": 3, "sync_status": "NEVER_RUN", "root_rule": {"rule_kind": "tag_glob_csv", "rule_value": ["*.latest*"]}, "robot_username": "quayadmin+mirror_robot"}
  • Sync the repositories by using the POST /api/v1/repository/{repository}/mirror/sync-now endpoint. For example:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/repository/<namespace>/<repo>/mirror/sync-now" \
         -H "Authorization: Bearer <access_token>"

    This command does not return output in the CLI.

  • Cancel the sync with the POST /api/v1/repository/{repository}/mirror/sync-cancel endpoint. For example:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/repository/<namespace>/<repo>/mirror/sync-cancel" \
         -H "Authorization: Bearer <access_token>"

    This command does not return output in the CLI.

  • After creating a mirror configuration, make changes with the PUT /api/v1/repository/{repository}/mirror command. For example, you might choose to disable automatic synchronizations:

    $ curl -X PUT "https://<quay-server.example.com>/api/v1/repository/<namespace>/<repo>/mirror" \
        -H "Authorization: Bearer <access_token>" \
        -H "Content-Type: application/json" \
        -d '{
            "is_enabled": <false>,
            "external_reference": "<external_reference>",
            "external_registry_username": "<external_registry_username>",
            "external_registry_password": "<external_registry_password>",
            "sync_start_date": "<sync_start_date>",
            "sync_interval": <sync_interval>,
            "robot_username": "<robot_username>",
            "skopeo_timeout_interval": 600,
            "root_rule": {
                "rule": "<rule>",
                "rule_type": "<rule_type>"
            }
        }'

    Where:

    "is_enabled": <false>

    Disables automatic synchronization.

Establishing quota with the Project Quay API

Quota policies in Project Quay set storage limits for organizations and users so that you can control registry capacity. You can create, view, update, and delete quota settings through the API.

Managing organization quota with the Project Quay API

To manage storage quota for an organization in Project Quay, you can use the organization quota API endpoints. You can check, create, change, or delete quota limitations.

When an organization is first created, it does not have an established quota.

Prerequisites
  • You have generated an OAuth access token.

Procedure
  1. To set a quota for an organization, use the POST /api/v1/organization/{orgname}/quota endpoint:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota" \
         -H "Authorization: Bearer <access_token>" \
         -H "Content-Type: application/json" \
         -d '{
             "limit_bytes": 10737418240,
             "limits": "10 Gi"
         }'
    Example output
    "Created"
  2. Use the GET /api/v1/organization/{orgname}/quota command to return information about the policy, including the ID number, which is required for other organization quota endpoints. For example:

    $ curl -k -X GET -H "Authorization: Bearer <token>" -H 'Content-Type: application/json'  https://example-registry-quay-quay-enterprise.apps.docs.gcp.quaydev.org/api/v1/organization/testorg/quota  | jq
    Example output
    [{"id": 1, "limit_bytes": 10737418240, "limit": "10.0 GiB", "default_config": false, "limits": [], "default_config_exists": false}]

    After you obtain the ID number, you can use the GET /api/v1/organization/{orgname}/quota/{quota_id} command to list the quota policy. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>" \
         -H "Authorization: Bearer <access_token>"
    Example output
    {"id": 1, "limit_bytes": 10737418240, "limit": "10.0 GiB", "default_config": false, "limits": [], "default_config_exists": false}
  3. Use the PUT /api/v1/organization/{orgname}/quota/{quota_id} command to modify the existing quota limitation. Note that this requires the policy ID. For example:

    $ curl -X PUT "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>" \
         -H "Authorization: Bearer <access_token>" \
         -H "Content-Type: application/json" \
         -d '{
             "limit_bytes": <limit_in_bytes>
         }'
    Example output
    {"id": 1, "limit_bytes": 21474836480, "limit": "20.0 GiB", "default_config": false, "limits": [], "default_config_exists": false}
  4. Delete an organization’s quota with the DELETE /api/v1/organization/{orgname}/quota/{quota_id} command. For example:

    $ curl -X DELETE "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>" \
         -H "Authorization: Bearer <access_token>"

    This command does not return output.

Setting quota limits for an organization by using the Project Quay API

To return a warning or deny image pushes when an organization exceeds its quota in Project Quay, you can create, list, update, and delete organization quota limits through the API.

Procedure
  1. Use the POST /api/v1/organization/{orgname}/quota/{quota_id}/limit command to create a quota policy that rejects images if they exceed the allotted quota. For example:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>/limit" \
         -H "Authorization: Bearer <access_token>" \
         -H "Content-Type: application/json" \
         -d '{
               "limit_bytes": 21474836480,
               "type": "Reject",
               "threshold_percent": 90
             }'

    where:

    type

    Specifies one of Reject or Warning.

    threshold_percent

    Specifies the quota threshold, in percent of quota.

    Example output
    "Created"
  2. Use the GET /api/v1/organization/{orgname}/quota/{quota_id}/limit command to obtain the ID of the quota limit. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>/limit" \
         -H "Authorization: Bearer <access_token>"
    Example output
    [{"id": 2, "type": "Reject", "limit_percent": 90}]
  3. Update the policy with the PUT /api/v1/organization/{orgname}/quota/{quota_id}/limit/{limit_id} endpoint. For example:

    $ curl -X PUT "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>/limit/<limit_id>" \
         -H "Authorization: Bearer <access_token>" \
         -H "Content-Type: application/json" \
         -d '{
               "type": "<type>",
               "threshold_percent": <threshold_percent>
             }'
    Example output
    {"id": 3, "limit_bytes": 10737418240, "limit": "10.0 GiB", "default_config": false, "limits": [{"id": 2, "type": "Warning", "limit_percent": 80}], "default_config_exists": false}
  4. Delete the quota limit with the DELETE /api/v1/organization/{orgname}/quota/{quota_id}/limit/{limit_id} endpoint:

    $ curl -X DELETE "https://<quay-server.example.com>/api/v1/organization/<orgname>/quota/<quota_id>/limit/<limit_id>" \
         -H "Authorization: Bearer <access_token>"

    This command does not return output.

Obtaining quota limits for the user with the Project Quay API

To view storage quota and limit policies for the logged-in user in Project Quay, you can call the user quota API endpoints.

Quota limits for users must be set on the Project Quay UI. The following APIs return the quota limits for the user that is logged in.

Procedure
  1. Use the GET /api/v1/user/quota command to return information about the quota limitations:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/user/quota" \
      -H "Authorization: Bearer <access_token>"
    Example output
    [{"id": 4, "limit_bytes": 2199023255552, "limit": "2.0 TiB", "default_config": false, "limits": [], "default_config_exists": false}]
  2. After you have received the quota ID, pass it in with the GET /api/v1/user/quota/{quota_id} endpoint to return information about the limitation:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/user/quota/{quota_id}" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"id": 4, "limit_bytes": 2199023255552, "limit": "2.0 TiB", "default_config": false, "limits": [], "default_config_exists": false}
  3. View the limitations by using the GET /api/v1/user/quota/{quota_id}/limit endpoint. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/user/quota/{quota_id}/limit" \
      -H "Authorization: Bearer <access_token>"
    Example output
    [{"id": 3, "type": "Reject", "limit_percent": 100}]
  4. Return additional information about the entire policy by using the GET /api/v1/user/quota/{quota_id}/limit/{limit_id} endpoint:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/user/quota/{quota_id}/limit/{limit_id}" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"id": 4, "limit_bytes": 2199023255552, "limit": "2.0 TiB", "default_config": false, "limits": [{"id": 3, "type": "Reject", "limit_percent": 100}], "default_config_exists": false}

Managing organizations by using the API

To create and manage organizations in Project Quay, you can use organization API endpoints. You can view organization details, manage members, configure proxy caches, and delete organizations.

Managing organization contact email with the API

Use the organization contact email setting to configure where automated system alerts are sent for an organization. The contact_email field allows multiple organizations to share the same notification address without requiring separate user accounts for each team.

Note

In the Project Quay web UI, the contact_email field is labeled as Organization creation: "Email (Optional)" and Organization Settings page: "Email".

The organization contact_email field has the following properties:

  • Receives namespace-level notifications (such as quota warnings and quota errors), billing and payment alerts (invoices, payment failures), and organization account recovery emails.

  • Can be shared across multiple organizations (useful for team distribution lists).

  • An optional setting; if left empty, notifications default to organization owners.

Note

When FEATURE_ORG_SHARED_EMAIL: false, Project Quay enforces email uniqueness by default so that the same address cannot be used by more than one user or organization entity. This is a backend restriction and not a UI-only rule. It applies during organization creation only, not when you later update an organization contact email. At creation time, the organization contact email cannot match any existing user account email in the system.

When you set FEATURE_ORG_SHARED_EMAIL: true in your config.yaml file, the same email address can be shared across multiple organizations and with at most one user account.

Note

For POST and PUT requests, the API accepts both email and contact_email fields. When both are provided, contact_email takes precedence. The email field is retained for backward compatibility, but new integrations should use contact_email.

Prerequisites
Procedure
  • To retrieve the current email configured for an organization, use the following GET /api/v1/organization/{orgname} endpoint:

    $ curl -X GET \
    -H "Authorization: Bearer <bearer_token>" \
    "https://<quay-server.example.com>/api/v1/organization/engineering"
    Example response
    {
      "name": "engineering",
      "email": "team-notifications@example.com",
      "is_admin": true
    }

    When an email address is not configured, the API response returns "email": "".

  • To set the contact email when creating an organization, pass the contact_email field by using the POST /api/v1/organization/ endpoint:

    $ curl -X POST \
    -H "Authorization: Bearer <bearer_token>" \
    -H "Content-Type: application/json" \
    -d '{"name": "engineering", "contact_email": "team-alerts@example.com"}' \
    "https://<quay-server.example.com>/api/v1/organization/"
  • To update the contact email for an existing organization, use the PUT /api/v1/organization/{orgname} endpoint:

    $ curl -X PUT \
    -H "Authorization: Bearer <bearer_token>" \
    -H "Content-Type: application/json" \
    -d '{"contact_email": "new-team-alerts@example.com"}' \
    "https://<quay-server.example.com>/api/v1/organization/engineering"
  • To remove the contact email, set contact_email to null or "" (empty string). System notifications default to organization owners:

    $ curl -X PUT \
    -H "Authorization: Bearer <bearer_token>" \
    -H "Content-Type: application/json" \
    -d '{"contact_email": ""}' \
    "https://<quay-server.example.com>/api/v1/organization/engineering"
  • Multiple organizations can share the same notification address (for example, a team distribution list):

    $ curl -X PUT -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
    -d '{"email": "devops-team@example.com"}' \
    "https://<quay-server.example.com>/api/v1/organization/engineering"
    $ curl -X PUT -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
    -d '{"email": "devops-team@example.com"}' \
    "https://<quay-server.example.com>/api/v1/organization/qa-team"
    Note

    With the default setting (FEATURE_ORG_SHARED_EMAIL: false), attempting to set an organization email to an address already registered to a user account returns Email has already been used: <email>.

    To allow the same email address to be shared across multiple organizations and with at most one user account, set FEATURE_ORG_SHARED_EMAIL: true in your config.yaml file.

Retrieving organization member information by using the API

To list organization members and collaborators or remove a member in Project Quay, you can call the organization members API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the GET /api/v1/organization/{orgname}/members endpoint to return a list of organization members:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/<orgname>/members" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"members": [{"name": "quayadmin", "kind": "user", "avatar": {"name": "quayadmin", "hash": "6d640d802fe23b93779b987c187a4b7a4d8fbcbd4febe7009bdff58d84498fba", "color": "#f7b6d2", "kind": "user"}, "teams": [{"name": "owners", "avatar": {"name": "owners", "hash": "6f0e3a8c0eb46e8834b43b03374ece43a030621d92a7437beb48f871e90f8d90", "color": "#c7c7c7", "kind": "team"}}], "repositories": ["testrepo"]}, {"name": "testuser", "kind": "user", "avatar": {"name": "testuser", "hash": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a", "color": "#6b6ecf", "kind": "user"}, "teams": [{"name": "owners", "avatar": {"name": "owners", "hash": "6f0e3a8c0eb46e8834b43b03374ece43a030621d92a7437beb48f871e90f8d90", "color": "#c7c7c7", "kind": "team"}}], "repositories": []}]}
  2. You can use the GET /api/v1/organization/{orgname}/collaborators endpoint to return a list of organization collaborators:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/{orgname}/collaborators" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"collaborators": [user-test]}
  3. Use the GET /api/v1/organization/{orgname}/members/{membername} endpoint to obtain more specific information about a user:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/<orgname>/members/<membername>" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"name": "quayadmin", "kind": "user", "avatar": {"name": "quayadmin", "hash": "6d640d802fe23b93779b987c187a4b7a4d8fbcbd4febe7009bdff58d84498fba", "color": "#f7b6d2", "kind": "user"}, "teams": [{"name": "owners", "avatar": {"name": "owners", "hash": "6f0e3a8c0eb46e8834b43b03374ece43a030621d92a7437beb48f871e90f8d90", "color": "#c7c7c7", "kind": "team"}}], "repositories": ["testrepo"]}
  4. Use the DELETE /api/v1/organization/{orgname}/members/{membername} endpoint to delete a team member.

    $ curl -X DELETE "https://<quay-server.example.com>/api/v1/organization/<orgname>/members/<membername>" \
      -H "Authorization: Bearer <access_token>"

    This command does not return output.

Managing an organization application by using the Project Quay API

To create, list, update, or delete organization applications in Project Quay, you can call the organization applications API endpoints with an OAuth access token.

Note

After you create an organization application in the UI, create and manage OAuth 2 access tokens from the application’s API Access Tokens page.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the POST /api/v1/organization/{orgname}/applications endpoint to create a new application for your organization. For example:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/organization/<orgname>/applications" \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{
            "name": "<app_name>",
            "redirect_uri": "<redirect_uri>",
            "application_uri": "<application_uri>",
            "description": "<app_description>",
            "avatar_email": "<avatar_email>"
          }'
    Example output
    {"name": "new-application", "description": "", "application_uri": "", "client_id": "E6GJSHOZMFBVNHTHNB53", "client_secret": "SANSWCWSGLVAUQ60L4Q4CEO3C1QAYGEXZK2VKJNI", "redirect_uri": "", "avatar_email": null}
  2. Use the GET /api/v1/organization/{orgname}/applications endpoint to return a list of all organization applications. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/<orgname>/applications" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"applications": [{"name": "test", "description": "", "application_uri": "", "client_id": "MCJ61D8KQBFS2DXM56S2", "client_secret": "J5G7CCX5QCA8Q5XZLWGI7USJPSM4M5MQHJED46CF", "redirect_uri": "", "avatar_email": null}, {"name": "new-token", "description": "", "application_uri": "", "client_id": "IG58PX2REEY9O08IZFZE", "client_secret": "2LWTWO89KH26P2CO4TWFM7PGCX4V4SUZES2CIZMR", "redirect_uri": "", "avatar_email": null}, {"name": "second-token", "description": "", "application_uri": "", "client_id": "6XBK7QY7ACSCN5XBM3GS", "client_secret": "AVKBOUXTFO3MXBBK5UJD5QCQRN2FWL3O0XPZZT78", "redirect_uri": "", "avatar_email": null}, {"name": "new-application", "description": "", "application_uri": "", "client_id": "E6GJSHOZMFBVNHTHNB53", "client_secret": "SANSWCWSGLVAUQ60L4Q4CEO3C1QAYGEXZK2VKJNI", "redirect_uri": "", "avatar_email": null}]}

    You can also return applications for a specific client by using the GET /api/v1/organization/{orgname}/applications/{client_id} endpoint. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/<orgname>/applications/<client_id>" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"name": "test", "description": "", "application_uri": "", "client_id": "MCJ61D8KQBFS2DXM56S2", "client_secret": "J5G7CCX5QCA8Q5XZLWGI7USJPSM4M5MQHJED46CF", "redirect_uri": "", "avatar_email": null}
  3. After creation, you can update organization applications, for example to add a redirect URI or a new description, by using the PUT /api/v1/organization/{orgname}/applications/{client_id} endpoint:

    $ curl -X PUT "https://quay-server.example.com/api/v1/organization/test/applications/12345" \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{
            "name": "Updated Application Name",
            "redirect_uri": "https://example.com/oauth/callback",
            "application_uri": "https://example.com",
            "description": "Updated description for the application",
            "avatar_email": "avatar@example.com"
          }'
  4. After creation, you can return application information by using the GET /api/v1/app/{client_id} endpoint:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/app/<client_id>" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"name": "new-application3", "description": "", "uri": "", "avatar": {"name": "new-application3", "hash": "a15d479002b20f211568fd4419e76686d2b88a4980a5b4c4bc10420776c5f6fe", "color": "#aec7e8", "kind": "app"}, "organization": {"name": "test", "email": "new-contact@test-org.com", "avatar": {"name": "test", "hash": "a15d479002b20f211568fd4419e76686d2b88a4980a5b4c4bc10420776c5f6fe", "color": "#aec7e8", "kind": "user"}, "is_admin": true, "is_member": true, "teams": {}, "ordered_teams": [], "invoice_email": true, "invoice_email_address": "billing@test-org.com", "tag_expiration_s": 1209600, "is_free_account": true, "quotas": [{"id": 2, "limit_bytes": 10737418240, "limits": [{"id": 1, "type": "Reject", "limit_percent": 90}]}], "quota_report": {"quota_bytes": 0, "configured_quota": 10737418240, "running_backfill": "complete", "backfill_status": "complete"}}}
  5. You can delete organization applications with the DELETE /api/v1/organization/{orgname}/applications/{client_id} endpoint. For example:

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

    This command does not return output.

Configuring a proxy cache for an organization by using the Project Quay API

To create, validate, view, or delete a proxy cache configuration for an organization in Project Quay, you can call the organization proxycache API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the POST /api/v1/organization/{orgname}/proxycache endpoint to create a proxy cache configuration for the organization.

    $ curl -X POST "https://<quay-server.example.com>/api/v1/organization/<orgname>/proxycache" \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{
            "upstream_registry": "<upstream_registry>"
            "upstream_registry_username": "your_robot_account_username"
            "upstream_registry_password": "your_robot_account_password"
          }'
  2. Use the POST /api/v1/organization/{orgname}/validateproxycache endpoint to validate the proxy configuration:

    $ curl -X POST "https://<quay-server.example.com>/api/v1/organization/{orgname}/validateproxycache" \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{
            "upstream_registry": "<upstream_registry>"
            "upstream_registry_username": "your_robot_account_username"
            "upstream_registry_password": "your_robot_account_password"
          }'
  3. Use the GET /api/v1/organization/{orgname}/proxycache endpoint to obtain information about the proxy cache. For example:

    $ curl -X GET "https://<quay-server.example.com>/api/v1/organization/{orgname}/proxycache" \
      -H "Authorization: Bearer <access_token>"
    Example output
    {"upstream_registry": "quay.io", "expiration_s": 86400, "insecure": false}
  4. Use the DELETE /api/v1/organization/{orgname}/proxycache endpoint to delete the proxy cache configuration:

    $ curl -X DELETE "https://<quay-server.example.com>/api/v1/organization/{orgname}/proxycache" \
      -H "Authorization: Bearer <access_token>"
    Example output
    "Deleted"

Automate repository and robot operations through the Red Hat Quay API

Automate repository permissions, auto-prune policies, and robot operations by using the Red Hat Quay API.

Managing repository permissions by using the Project Quay API

To create, view, and delete user and team access on a repository in Project Quay, you can manage repository permissions through the API.

Managing user permissions by using the Project Quay API

To view, change, or remove a user role on a repository in Project Quay, you can call the repository user permissions API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the GET /api/v1/repository/{repository}/permissions/user/{username} endpoint to obtain repository permissions for a user. For example:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<repository_path>/permissions/user/<username>"
    Example output
    {"role": "read", "name": "testuser", "is_robot": false, "avatar": {"name": "testuser", "hash": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a", "color": "#6b6ecf", "kind": "user"}, "is_org_member": false}
  2. Return all user permissions with the GET /api/v1/repository/{repository}/permissions/user/ endpoint:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<namespace>/<repository>/permissions/user/"
    Example output
    {"permissions": {"quayadmin": {"role": "admin", "name": "quayadmin", "is_robot": false, "avatar": {"name": "quayadmin", "hash": "6d640d802fe23b93779b987c187a4b7a4d8fbcbd4febe7009bdff58d84498fba", "color": "#f7b6d2", "kind": "user"}, "is_org_member": true}, "test+example": {"role": "admin", "name": "test+example", "is_robot": true, "avatar": {"name": "test+example", "hash": "3b03050c26e900500437beee4f7f2a5855ca7e7c5eab4623a023ee613565a60e", "color": "#a1d99b", "kind": "robot"}, "is_org_member": true}}}
  3. Alternatively, use the GET /api/v1/repository/{repository}/permissions/user/{username}/transitive endpoint to return only the repository permission for the user:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<repository_path>/permissions/user/<username>/transitive"
    Example output
    {"permissions": [{"role": "admin"}]}
  4. Change the user’s permissions, such as making the user an admin, by using the PUT /api/v1/repository/{repository}/permissions/user/{username} endpoint. For example:

    $ curl -X PUT \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{"role": "<role>"}' \
      "https://quay-server.example.com/api/v1/repository/<repository_path>/permissions/user/<username>"
    Example output
    {"role": "admin", "name": "testuser", "is_robot": false, "avatar": {"name": "testuser", "hash": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a", "color": "#6b6ecf", "kind": "user"}, "is_org_member": false}
  5. Delete user permissions by using the DELETE /api/v1/repository/{repository}/permissions/user/{username} endpoint. For example:

    $ curl -X DELETE \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<namespace>/<repository>/permissions/user/<username>"

    This command does not return output.

Managing team permissions by using the Project Quay API

To view, change, or remove a team role on a repository in Project Quay, you can call the repository team permissions API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Return permissions for a specified team by using the GET /api/v1/repository/{repository}/permissions/team/{teamname} endpoint:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<namespace>/<repository>/permissions/team/<teamname>"
    Example output
    {"role": "write"}
  2. Return permissions for all teams with the GET /api/v1/repository/{repository}/permissions/team/ endpoint. For example:

    $ curl -X GET \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<namespace>/<repository>/permissions/team/"
    Example output
    {"permissions": {"ironmanteam": {"role": "read", "name": "ironmanteam", "avatar": {"name": "ironmanteam", "hash": "8045b2361613622183e87f33a7bfc54e100a41bca41094abb64320df29ef458d", "color": "#969696", "kind": "team"}}, "sillyteam": {"role": "read", "name": "sillyteam", "avatar": {"name": "sillyteam", "hash": "f275d39bdee2766d2404e2c6dbff28fe290969242e9fcf1ffb2cde36b83448ff", "color": "#17becf", "kind": "team"}}}}
  3. Change permissions for a specified team by using the PUT /api/v1/repository/{repository}/permissions/team/{teamname} command. For example:

    $ curl -X PUT \
      -H "Authorization: Bearer <access_token>" \
      -H "Content-Type: application/json" \
      -d '{"role": "<role>"}' \
      "https://quay-server.example.com/api/v1/repository/<namespace>/<repository>/permissions/team/<teamname>"
    Example output
    {"role": "admin", "name": "superteam", "avatar": {"name": "superteam", "hash": "48cb6d114200039fed5c601480653ae7371d5a8849521d4c3bf2418ea013fc0f", "color": "#9467bd", "kind": "team"}}
  4. Delete team permissions with the DELETE /api/v1/repository/{repository}/permissions/team/{teamname} command. For example:

    $ curl -X DELETE \
      -H "Authorization: Bearer <access_token>" \
      "https://quay-server.example.com/api/v1/repository/<namespace>/<repository>/permissions/team/<teamname>"

    This command does not return output in the CLI.

Managing auto-prune policies by using the Project Quay API

To create, retrieve, update, and delete auto-prune policies for organizations, repositories, and users in Project Quay, you can use the auto-prune policy API endpoints.

Creating and configuring repositories

To create a repository and manage its visibility, details, and description in Project Quay, you can call the repository API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Enter the following command to create a repository by using the POST /api/v1/repository endpoint:

    $ curl -X POST \
      -H "Authorization: Bearer <bearer_token>" \
      -H "Content-Type: application/json" \
      -d '{
        "repository": "<new_repository_name>",
        "visibility": "<private>",
        "description": "<This is a description of the new repository>."
      }' \
      "https://quay-server.example.com/api/v1/repository"
    Example output
    {"namespace": "quayadmin", "name": "<new_repository_name>", "kind": "image"}
  2. You can list repositories with the GET /api/v1/repository endpoint. For example:

    $ curl -X GET \
      -H "Authorization: Bearer <ACCESS_TOKEN>" \
      "https://quay-server.example.com/api/v1/repository?public=true&starred=false&namespace=<NAMESPACE>"
    Example output
    {"repositories": [{"namespace": "quayadmin", "name": "busybox", "description": null, "is_public": false, "kind": "image", "state": "MIRROR", "is_starred": false, "quota_report": {"quota_bytes": 2280675, "configured_quota": 2199023255552}}]}
  3. Change visibility from public to private with the POST /api/v1/repository/{repository}/changevisibility endpoint:

    $ curl -X POST \
      -H "Authorization: Bearer <ACCESS_TOKEN>" \
      -H "Content-Type: application/json" \
      -d '{
            "visibility": "private"
          }' \
      "https://quay-server.example.com/api/v1/repository/<NAMESPACE>/<REPO_NAME>/changevisibility"
    Example output
    {"success": true}
  4. You can check the Project Quay UI, or you can enter the following GET /api/v1/repository/{repository} command to return details about a repository:

    $ curl -X GET -H "Authorization: Bearer <bearer_token>" "<quay-server.example.com>/api/v1/repository/<namespace>/<repository_name>"
    Example output
    {"detail": "Not Found", "error_message": "Not Found", "error_type": "not_found", "title": "not_found", "type": "http://quay-server.example.com/api/v1/error/not_found", "status": 404}
  5. Update repository descriptions with the PUT /api/v1/repository/{repository} endpoint:

    $ curl -X PUT \
      -H "Authorization: Bearer <bearer_token>" \
      -H "Content-Type: application/json" \
      -d '{
            "description": "This is an updated description for the repository."
          }' \
      "https://quay-server.example.com/api/v1/repository/<NAMESPACE>/<REPOSITORY>"
    Example output
    {"success": true}
  6. Enter the following command to delete a repository by using the DELETE /api/v1/repository/{repository} endpoint:

    $ curl -X DELETE   -H "Authorization: Bearer <bearer_token>" "<quay-server.example.com>/api/v1/repository/<namespace>/<repository_name>"

    This command does not return output in the CLI.

Creating and configuring robot accounts by using the Project Quay API

To create, retrieve, update, and delete robot accounts for organizations and users in Project Quay, you can use the robot account API endpoints.

Creating a robot account by using the Project Quay API

To automate access to your repositories, you can create a robot account by using the Project Quay API. You can create robot accounts for an organization or for your own user account.

Prerequisites
  • You have created an OAuth access token.

Procedure
  • Enter the following command to create a new robot account for an organization by using the PUT /api/v1/organization/{orgname}/robots/{robot_shortname} endpoint:

    $ curl -X PUT   -H "Authorization: Bearer <bearer_token>" "https://<quay-server.example.com>/api/v1/organization/<organization_name>/robots/<robot_name>"
    Example output
    {"name": "orgname+robot-name", "created": "Fri, 10 May 2024 15:11:00 -0000", "last_accessed": null, "description": "", "token": "<example_secret>", "unstructured_metadata": null}
  • Enter the following command to create a new robot account for the current user with the PUT /api/v1/user/robots/{robot_shortname} endpoint:

    $ curl -X PUT   -H "Authorization: Bearer <bearer_token>" "https://<quay-server.example.com>/api/v1/user/robots/<robot_name>"
    Example output
    {"name": "quayadmin+robot-name", "created": "Fri, 10 May 2024 15:24:57 -0000", "last_accessed": null, "description": "", "token": "<example_secret>", "unstructured_metadata": null}

Obtaining robot account information by using the Project Quay API

To review robot account details and permissions for an organization or user in Project Quay, you can call the robot account API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  • Use the GET /api/v1/organization/{orgname}/robots/{robot_shortname} API endpoint to return information for a robot for an organization:

    $ curl -X GET \
      -H "Authorization: Bearer <bearer_token>" \
      "https://quay-server.example.com/api/v1/organization/<ORGNAME>/robots/<ROBOT_SHORTNAME>"
    Example output
    {"name": "test+example", "created": "Mon, 25 Nov 2024 16:25:16 -0000", "last_accessed": null, "description": "", "token": "string", "unstructured_metadata": {}}
  • Use the GET /api/v1/organization/{orgname}/robots/{robot_shortname}/permissions endpoint to return the list of permissions for a specific organization robot:

    $ curl -X GET \
      -H "Authorization: Bearer <bearer_token>" \
      "https://quay-server.example.com/api/v1/organization/<ORGNAME>/robots/<ROBOT_SHORTNAME>/permissions"
    Example output
    {"permissions": [{"repository": {"name": "testrepo", "is_public": true}, "role": "admin"}]}
  • Use the GET /api/v1/user/robots/{robot_shortname} API endpoint to return the user’s robot with the specified name:

    $ curl -X GET \
      -H "Authorization: Bearer <bearer_token>" \
      "https://quay-server.example.com/api/v1/user/robots/<ROBOT_SHORTNAME>"
    Example output
    {"name": "quayadmin+mirror_robot", "created": "Wed, 15 Jan 2025 17:22:09 -0000", "last_accessed": null, "description": "", "token": "<token_example>", "unstructured_metadata": {}}
  • Use the GET /api/v1/user/robots/{robot_shortname}/permissions API endpoint to return a list of permissions for the user robot:

    $ curl -X GET \
      -H "Authorization: Bearer <bearer_token>" \
      "https://quay-server.example.com/api/v1/user/robots/<ROBOT_SHORTNAME>/permissions"
    Example output
    {"permissions": [{"repository": {"name": "busybox", "is_public": false}, "role": "write"}]}

Deleting a robot account by using the Project Quay API

To remove a robot account that you no longer need, you can delete it by using the Project Quay API. You can delete robot accounts that belong to an organization or to your own user account.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Enter the following command to delete a robot account for an organization by using the DELETE /api/v1/organization/{orgname}/robots/{robot_shortname} endpoint:

    $ curl -X DELETE \
      -H "Authorization: Bearer <bearer_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/robots/<robot_shortname>"
  2. The CLI does not return information when deleting a robot account with the API. To confirm deletion, you can check the Project Quay UI, or you can enter the following GET /api/v1/organization/{orgname}/robots command to see if details are returned for the robot account:

    $ curl -X GET   -H "Authorization: Bearer <bearer_token>"   "https://<quay-server.example.com>/api/v1/organization/<organization_name>/robots"
    Example output
    {"robots": []}
  3. Enter the following command to delete a robot account for the current user with the DELETE /api/v1/user/robots/{robot_shortname} endpoint:

    $ curl -X DELETE \
      -H "Authorization: Bearer <bearer_token>" \
      "<quay-server.example.com>/api/v1/user/robots/<robot_shortname>"
  4. The CLI does not return information when deleting a robot account for the current user with the API. To confirm deletion, you can check the Project Quay UI, or you can enter the following GET /api/v1/user/robots/{robot_shortname} command to see if details are returned for the robot account:

    $ curl -X GET \
      -H "Authorization: Bearer <bearer_token>" \
      "<quay-server.example.com>/api/v1/user/robots/<robot_shortname>"
    Example output
    {"message":"Could not find robot with specified username"}

Automate tags and teams through the Red Hat Quay API

Automate tag management, team operations, and registry search by using the Red Hat Quay API.

Searching against registry context

To find repositories, entities, and other registry resources in Project Quay, you can use the search API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  • Use the GET /api/v1/find/repositories endpoint to get a list of apps and repositories that match the specified query:

    $ curl -X GET "https://quay-server.example.com/api/v1/find/repositories?query=<repo_name>&page=1&includeUsage=true" \
      -H "Authorization: Bearer <bearer_token>"
    Example output
    {"results": [], "has_additional": false, "page": 2, "page_size": 10, "start_index": 10}
  • Use the GET /api/v1/find/all endpoint to get a list of entities and resources that match the specified query:

    $ curl -X GET "https://quay-server.example.com/api/v1/find/all?query=<mysearchterm>" \
      -H "Authorization: Bearer <bearer_token>"
    Example output
    {"results": [{"kind": "repository", "title": "repo", "namespace": {"title": "user", "kind": "user", "avatar": {"name": "quayadmin", "hash": "6d640d802fe23b93779b987c187a4b7a4d8fbcbd4febe7009bdff58d84498fba", "color": "#f7b6d2", "kind": "user"}, "name": "quayadmin", "score": 1, "href": "/user/quayadmin"}, "name": "busybox", "description": null, "is_public": false, "score": 4.0, "href": "/repository/quayadmin/busybox"}]}
  • Use the GET /api/v1/entities/{prefix} endpoint to get a list of entities that match the specified prefix.

    $ curl -X GET "https://quay-server.example.com/api/v1/entities/<prefix>?includeOrgs=<true_or_false>&includeTeams=<true_or_false>&namespace=<namespace>" \
      -H "Authorization: Bearer <bearer_token>"
    Example output
    {"results": [{"name": "quayadmin", "kind": "user", "is_robot": false, "avatar": {"name": "quayadmin", "hash": "6d640d802fe23b93779b987c187a4b7a4d8fbcbd4febe7009bdff58d84498fba", "color": "#f7b6d2", "kind": "user"}}]}

Managing tags with the Project Quay API

To change, restore, list, or delete repository tags in Project Quay, you can use the tag API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the PUT /api/v1/repository/{repository}/tag/{tag} endpoint to change which image a tag points to or create a new tag:

    $ curl -X PUT "https://quay-server.example.com/api/v1/repository/<namespace>/<repo_name>/tag/<tag_name>" \
      -H "Authorization: Bearer <ACCESS_TOKEN>" \
      -H "Content-Type: application/json" \
      -d '{"manifest_digest": "<MANIFEST_DIGEST>"}'
    Example output
    "Updated"
  2. Use the POST /api/v1/repository/{repository}/tag/{tag}/restore endpoint to restore a repository tag back to a previous image in the repository:

    $ curl -X POST "https://quay-server.example.com/api/v1/repository/<namespace>/<repo_name>/tag/<tag_name>/restore" \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json" \
      -d '{"manifest_digest": "sha256:<your_manifest_digest>"}'
    Example output
    {}
  3. Use the GET /api/v1/repository/{repository}/tag/ endpoint to obtain a list of repository tags:

    $ curl -X GET "https://quay-server.example.com/api/v1/repository/<namespace>/<repo_name>/tag/" \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json"
    Example output
    {"tags": [{"name": "test", "reversion": true, "start_ts": 1740496373, "manifest_digest": "sha256:d08334991a3dba62307016833083d6433f489ab0f7d36d0a4771a20b4569b2f6", "is_manifest_list": false, "size": 2280303, "last_modified": "Tue, 25 Feb 2025 15:12:53 -0000"}, {"name": "test", "reversion": false, "start_ts": 1740495442, "end_ts": 1740496373, "manifest_digest": "sha256:d08334991a3dba62307016833083d6433f489ab0f7d36d0a4771a20b4569b2f6", "is_manifest_list": false, "size": 2280303, "last_modified": "Tue, 25 Feb 2025 14:57:22 -0000", "expiration": "Tue, 25 Feb 2025 15:12:53 -0000"}, {"name": "test", "reversion": false, "start_ts": 1740495408, "end_ts": 1740495442, "manifest_digest": "sha256:d08334991a3dba62307016833083d6433f489ab0f7d36d0a4771a20b4569b2f6", "is_manifest_list": false, "size": 2280303, "last_modified": "Tue, 25 Feb 2025 14:56:48 -0000", "expiration": "Tue, 25 Feb 2025 14:57:22 -0000"}], "page": 1, "has_additional": false}
  4. Use the DELETE /api/v1/repository/{repository}/tag/{tag} endpoint to delete a tag from a repository:

    $ curl -X DELETE "https://quay-server.example.com/api/v1/repository/<namespace>/<repo_name>/tag/<tag_name>" \
      -H "Authorization: Bearer <your_access_token>"

    This command does not return output in the CLI.

Managing teams by using the API

Organization teams in Project Quay group users for shared repository access. You can manage teams and membership by using the API.

Managing team members and repository permissions by using the API

To add, invite, or remove members of an organization team in Project Quay, you can use the team member API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  • Enter the PUT /api/v1/organization/{orgname}/team/{teamname}/members/{membername} command to add or invite a member to an existing team:

    $ curl -X PUT \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>/members/<member_name>"
    Example output
    {"name": "testuser", "kind": "user", "is_robot": false, "avatar": {"name": "testuser", "hash": "d51d17303dc3271ac3266fb332d7df919bab882bbfc7199d2017a4daac8979f0", "color": "#5254a3", "kind": "user"}, "invited": false}
  • Enter the DELETE /api/v1/organization/{orgname}/team/{teamname}/members/{membername} command to remove a member of a team:

    $ curl -X DELETE \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>/members/<member_name>"

    This command does not return output in the CLI. To ensure that a member has been deleted, you can enter the GET /api/v1/organization/{orgname}/team/{teamname}/members command and ensure that the member is not returned in the output.

    $ curl -X GET \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>/members"
    Example output
    {"name": "owners", "members": [{"name": "quayadmin", "kind": "user", "is_robot": false, "avatar": {"name": "quayadmin", "hash": "b28d563a6dc76b4431fc7b0524bbff6b810387dac86d9303874871839859c7cc", "color": "#17becf", "kind": "user"}, "invited": false}, {"name": "test-org+test", "kind": "user", "is_robot": true, "avatar": {"name": "test-org+test", "hash": "aa85264436fe9839e7160bf349100a9b71403a5e9ec684d5b5e9571f6c821370", "color": "#8c564b", "kind": "robot"}, "invited": false}], "can_edit": true}
  • You can enter the PUT /api/v1/organization/{orgname}/team/{teamname}/invite/{email} command to invite a user, by email address, to an existing team:

    $ curl -X PUT \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>/invite/<email>"
  • You can enter the DELETE /api/v1/organization/{orgname}/team/{teamname}/invite/{email} command to delete the invite of an email address to join a team. For example:

    $ curl -X DELETE \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>/invite/<email>"

Setting the role of a team within an organization by using the API

To view repository permissions for a team or set a team’s role in an Project Quay organization, you can use the organization team API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Enter the following GET /api/v1/organization/{orgname}/team/{teamname}/permissions command to return a list of repository permissions for the organization’s team. Note that your team must have been added to a repository for this command to return information.

    $ curl -X GET \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>/permissions"
    Example output
    {"permissions": [{"repository": {"name": "api-repo", "is_public": true}, "role": "admin"}]}
  2. You can create or update a team within an organization to have a specified role of admin, member, or creator using the PUT /api/v1/organization/{orgname}/team/{teamname} command. For example:

    $ curl -X PUT \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json" \
      -d '{
        "role": "<role>"
      }' \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>"
    Example output
    {"name": "testteam", "description": "", "can_view": true, "role": "creator", "avatar": {"name": "testteam", "hash": "827f8c5762148d7e85402495b126e0a18b9b168170416ed04b49aae551099dc8", "color": "#ff7f0e", "kind": "team"}, "new_team": false}

Deleting a team within an organization by using the API

To delete a team from an organization in Project Quay, you can use the organization team API endpoint with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  • You can delete a team within an organization by entering the DELETE /api/v1/organization/{orgname}/team/{teamname} command:

    $ curl -X DELETE \
      -H "Authorization: Bearer <your_access_token>" \
      "<quay-server.example.com>/api/v1/organization/<organization_name>/team/<team_name>"

    This command does not return output in the CLI.

Build container images from Dockerfiles in Red Hat Quay

Build container images from Dockerfiles by using the Red Hat Quay UI or API, including starting builds and creating build triggers.

Container image builds

Project Quay can build container images from Dockerfiles on worker nodes. You can start builds manually or automatically from source-control events so that registry images stay aligned with your code.

Builds are supported on Red Hat Quay on OpenShift Container Platform and Kubernetes. A build manager coordinates build jobs. You can run builders on bare metal nodes or as virtual (unprivileged container) builders, depending on isolation needs and available infrastructure.

When you plan builds, decide whether Project Quay should own image builds in your pipeline or whether an external CI system should push finished images into the registry. If you use Project Quay builds, choose a builder strategy and confirm networking constraints for your cluster.

Note

Running builds directly in a container on bare metal does not provide the same isolation as virtual machines, but it still provides meaningful process isolation.

Building container images

The Project Quay builds feature supports building Docker and Podman container images from Dockerfiles. You can create containerized applications by defining build contexts and using base images from public repositories.

supports the ability to build Docker and Podman container images. This functionality is valuable for developers and organizations who rely on container and container orchestration.

Build contexts

When building an image with Docker or Podman, a directory is specified to become the build context. This is true for both manual Builds and Build triggers, because the Build that is created by is not different than running docker build or podman build on your local machine.

Build contexts are always specified in the subdirectory from the Build setup, and fallback to the root of the Build source if a directory is not specified.

When a build is triggered, Build workers clone the Git repository to the worker machine, and then enter the Build context before conducting a Build.

For Builds based on .tar archives, Build workers extract the archive and enter the Build context. For example:

Extracted Build archive
example
├── .git
├── Dockerfile
├── file
└── subdir
    └── Dockerfile

Imagine that the Extracted Build archive is the directory structure got a Github repository called example. If no subdirectory is specified in the Build trigger setup, or when manually starting the Build, the Build operates in the example directory.

If a subdirectory is specified in the Build trigger setup, for example, subdir, only the Dockerfile within it is visible to the Build. This means that you cannot use the ADD command in the Dockerfile to add file, because it is outside of the Build context.

Unlike Docker Hub, the Dockerfile is part of the Build context on As a result, it must not appear in the .dockerignore file.

Starting a new build

Starting a build creates a container image from a Dockerfile in Project Quay. You can start builds manually by uploading a Dockerfile or automatically by using build triggers.

Prerequisites
  • You have navigated to the Builds page of your repository.

Procedure
  1. On the Builds page, click Start New Build.

  2. When prompted, click Upload Dockerfile to upload a Dockerfile or an archive that contains a Dockerfile at the root directory.

  3. Click Start Build.

    Note
    • Currently, users cannot specify the Docker build context when manually starting a build.

    • Currently, BitBucket is unsupported on the Project Quay v2 UI.

  4. You are redirected to the build, which can be viewed in real-time. Wait for the Dockerfile build to be completed and pushed.

  5. Optional. you can click Download Logs to download the logs, or Copy Logs to copy the logs.

  6. Click the back button to return to the Repository Builds page, where you can view the build history.

    Build history v2 UI

Creating a build trigger

To automate container image builds from your Git repositories, you can create a custom Git build trigger in Project Quay. Build triggers automatically build and push images when you push code to your Git repository.

The following steps can be replicated to create a build trigger using Github, Gitlab, or Bitbucket, however, you must configure the credentials for these services in your config.yaml file.

Note
  • If you want to use Github to create a build trigger, you must configure Github to be used with Project Quay by creating an OAuth application. For more information, see "Creating an OAuth application Github".

Procedure
  1. Log in to your Project Quay registry.

  2. In the navigation pane, click Repositories.

  3. Click Create Repository.

  4. Click the Builds tab.

  5. On the Builds page, click Create Build Trigger.

  6. Select the desired platform, for example, Github, Bitbucket, Gitlab, or use a custom Git repository. For this example, click Custom Git Repository Push.

  7. Enter a custom Git repository name, for example, git@github.com:<username>/<repo>.git. Then, click Next.

  8. When prompted, configure the tagging options by selecting one of, or both of, the following options:

    • Tag manifest with the branch or tag name. When selecting this option, the built manifest the name of the branch or tag for the git commit are tagged.

    • Add latest tag if on default branch. When selecting this option, the built manifest with latest if the build occurred on the default branch for the repository are tagged.

      Optionally, you can add a custom tagging template. There are multiple tag templates that you can enter here, including using short SHA IDs, timestamps, author names, committer, and branch names from the commit as tags. For more information, see "Tag naming for build triggers".

      After you have configured tagging, click Next.

  9. When prompted, select the location of the Dockerfile to be built when the trigger is invoked. If the Dockerfile is located at the root of the git repository and named Dockerfile, enter /Dockerfile as the Dockerfile path. Then, click Next.

  10. When prompted, select the context for the Docker build. If the Dockerfile is located at the root of the Git repository, enter / as the build context directory. Then, click Next.

  11. Optional. Choose an optional robot account. This allows you to pull a private base image during the build process. If you know that a private base image is not used, you can skip this step.

  12. Click Next. Check for any verification warnings. If necessary, fix the issues before clicking Finish.

  13. You are alerted that the trigger has been successfully activated. Note that using this trigger requires the following actions:

    • You must give the following public key read access to the git repository.

    • You must set your repository to POST to the following URL to trigger a build.

      Save the SSH Public Key, then click Return to <organization_name>/<repository_name>. You are redirected to the Builds page of your repository.

  14. On the Builds page, you now have a build trigger. For example:

    Example Build trigger

    After you have created a custom Git trigger, additional steps are required. Continue on to "Setting up a custom Git trigger".

    If you are setting up a build trigger for Github, Gitlab, or Bitbucket, continue on to "Manually triggering a build".

Managing builds by using the Project Quay API

To list, activate, start, update, or delete build triggers in Project Quay, you can use the build trigger API endpoints with an OAuth access token.

Prerequisites
  • You have created an OAuth access token.

Procedure
  1. Use the GET /api/v1/repository/{repository}/trigger/ endpoint to list the triggers for the specified repository:

    $ curl -X GET "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/" \
      -H "Authorization: Bearer <your_access_token>"
    Example output
    {"triggers": [{"id": "32ca5eae-a29f-46c7-8f44-3221ca417c92", "service": "custom-git", "is_active": false, "build_source": null, "repository_url": null, "config": {}, "can_invoke": true, "enabled": true, "disabled_reason": null}]}
  2. Use the POST /api/v1/repository/{repository}/trigger/{trigger_uuid}/activate endpoint to activate the specified build trigger.

    $ curl -X POST "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/example-trigger-uuid/activate" \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json" \
      -d '{
        "config": {
          "branch": "main"
        },
        "pull_robot": "example+robot"
      }'
  3. Use the POST /api/v1/repository/{repository}/trigger/{trigger_uuid}/start endpoint to manually start the build from the specified trigger:

    $ curl -X POST "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/example-trigger-uuid/start" \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json" \
      -d '{
        "branch_name": "main",
        "commit_sha": "abcdef1234567890",
        "refs": "refs/heads/main"
      }'
  4. Use the GET /api/v1/repository/{repository}/trigger/{trigger_uuid}/builds endpoint to list the builds started by the specified trigger:

    $ curl -X GET "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/example-trigger-uuid/builds?limit=10" \
      -H "Authorization: Bearer <your_access_token>"
  5. Use the GET /api/v1/repository/{repository}/trigger/{trigger_uuid} endpoint to get information for the specified build trigger:

    $ curl -X GET "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/example-trigger-uuid" \
      -H "Authorization: Bearer <your_access_token>"
  6. Use the PUT /api/v1/repository/{repository}/trigger/{trigger_uuid} endpoint to update the specified build trigger:

    $ curl -X PUT "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/example-trigger-uuid" \
      -H "Authorization: Bearer <your_access_token>" \
      -H "Content-Type: application/json" \
      -d '{"enabled": true}'
  7. Use the DELETE /api/v1/repository/{repository}/trigger/{trigger_uuid} endpoint to delete the specified build trigger:

    $ curl -X DELETE "https://quay-server.example.com/api/v1/repository/example_namespace/example_repo/trigger/example-trigger-uuid" \
      -H "Authorization: Bearer <your_access_token>"

Configure build triggers for Red Hat Quay

Configure Git, webhook, and GitHub App build triggers, including credentials, SSH keys, and manual build starts.

Setting up a custom Git trigger

To complete the setup of your custom Git build trigger in Project Quay, you must provide read access to the SSH public key and configure a webhook endpoint. These steps enable your Git repository to automatically trigger builds when you push code.

These steps are only required if you are using a custom Git trigger.

Obtaining build trigger credentials

To configure your custom Git trigger, you can obtain the SSH public key and webhook endpoint URL from the Project Quay user interface. These credentials are available on the Builds page of your repository.

Prerequisites
  • You have created a custom Git trigger.

Procedure
  1. On the Builds page of your repository, click the menu kebab for your custom Git trigger.

  2. Click View Credentials.

  3. Save the SSH Public Key and Webhook Endpoint URL.

    The key and the URL are available by selecting View Credentials from the Settings, or gear icon.

SSH public key access

SSH public key access in Project Quay enables builder instances to clone Git repositories for custom build triggers. Install the SSH public key that Project Quay generates in your Git server configuration, either by adding it to the authorized_keys file or using Deploy Keys.

Depending on the Git server configuration, you can install the SSH public key that Project Quay generates for a custom Git trigger in several ways.

For example, the Getting Git on a Server documentation describes how to configure a Git server on a Linux-based machine with a focus on managing repositories and access control through SSH. In this procedure, a small server adds the keys to the $HOME/.ssh/authorize_keys folder, which provides access for builders to clone the repository.

For any Git repository management software that is not officially supported, the software usually provides a field to input the key, often labeled as Deploy Keys.

Additional resources

Webhook reference

The webhook reference provides the JSON payload format required to trigger builds in Project Quay. You must POST a JSON payload with commit, ref, and default_branch fields to the webhook URL to automatically start a build.

Note

This request requires a Content-Type header containing application/json in order to be valid.

Example webhook
{
  "commit": "1c002dd",                                   // required
  "ref": "refs/heads/master",                            // required
  "default_branch": "master",                            // required
  "commit_info": {                                       // optional
    "url": "gitsoftware.com/repository/commits/1234567", // required
    "message": "initial commit",                         // required
    "date": "timestamp",                                 // required
    "author": {                                          // optional
      "username": "user",                                // required
      "avatar_url": "gravatar.com/user.png",             // required
      "url": "gitsoftware.com/users/user"                // required
    },
    "committer": {                                       // optional
      "username": "user",                                // required
      "avatar_url": "gravatar.com/user.png",             // required
      "url": "gitsoftware.com/users/user"                // required
    }
  }
}

This can typically be accomplished with a post-receive Git hook, however it does depend on your server setup.

Tag naming for build triggers

Tag naming for build triggers in Project Quay lets you create custom tags using templates that include commit information such as SHA, branch name, author, and date. You can use these templates to automatically tag your built images with meaningful identifiers based on the Git commit that triggered the build.

One option is to include any string of characters assigned as a tag for each built image. Alternatively, you can use the following tag templates on the Configure Tagging section of the build trigger to tag images with information from each commit:

Configure Tagging

  • ${commit}: Full SHA of the issued commit

  • ${parsed_ref.branch}: Branch information (if available)

  • ${parsed_ref.tag}: Tag information (if available)

  • ${parsed_ref.remote}: The remote name

  • ${commit_info.date}: Date when the commit was issued

  • ${commit_info.author.username}: Username of the author of the commit

  • ${commit_info.short_sha}: First 7 characters of the commit SHA

  • ${committer.properties.username}: Username of the committer

This list is not complete, but does contain the most useful options for tagging purposes. You can find the complete tag template schema in the Project Quay source repository.

Skipping a source control-triggered build

You can skip source control-triggered builds in Project Quay by adding [skip build] or [build skip] to your commit message. This prevents the build system from automatically building images for commits that do not require new builds.

Manually triggering a build

Manual build triggering in Project Quay lets you start builds on demand without waiting for automatic triggers from source control. You can manually trigger builds from the Builds page by selecting a build trigger and specifying a commit ID.

Procedure
  1. On the Builds page, Start new build.

  2. When prompted, select Invoke Build Trigger.

  3. Click Run Trigger Now to manually start the process.

  4. Enter a commit ID from which to initiate the build, for example, 1c002dd.

    After the build starts, you can see the build ID on the Repository Builds page.

Creating an OAuth application in GitHub

To enable GitHub integration for automated builds in Project Quay, you can create an OAuth application in GitHub. This allows Project Quay to access GitHub repositories and trigger container image builds when commits or pull requests are made.

Procedure
  1. Log into GitHub Enterprise.

  2. In the navigation pane, select your username → Your organizations.

  3. In the navigation pane, select ApplicationsDeveloper Settings.

  4. In the navigation pane, click OAuth AppsNew OAuth App. You are navigated to the following page:

    Register a new OAuth application

  5. Enter a name for the application in the Application name textbox.

  6. In the Homepage URL textbox, enter your Project Quay URL.

    Note

    If you are using public GitHub, the Homepage URL entered must be accessible by your users. It can still be an internal URL.

  7. In the Authorization callback URL, enter https://<RED_HAT_QUAY_URL>/oauth2/github/callback.

  8. Click Register application to save your settings.

  9. When the new application’s summary is shown, record the Client ID and the Client Secret shown for the new application.

Work with OCI artifacts, Helm charts, and image signing

Push OCI artifacts and Helm charts, attach referrers to image tags, and sign content with Cosign in Red Hat Quay.

Open Container Initiative support

Project Quay supports Open Container Initiative image and distribution formats beyond Docker manifests. You can store Helm charts and other OCI media types in the registry.

In addition to container images, a variety of artifacts have emerged that support not just individual applications, but also the Kubernetes platform as a whole. These range from Open Policy Agent (OPA) policies for security and governance to Helm charts and Operators that aid in application deployment.

is a private container registry that not only stores container images, but also supports an entire ecosystem of tooling to aid in the management of containers. strives to be as compatible as possible with the OCI 1.1 Image and Distribution specifications, and supports common media types like Helm charts (as long as they pushed with a version of Helm that supports OCI) and a variety of arbitrary media types within the manifest or layer components of container images.

In addition to its expanded support for novel media types, ensures compatibility with Docker images, including V2_2 and V2_1 formats. This compatibility with Docker V2_2 and V2_1 images demonstrates commitment to providing a seamless experience for Docker users. Moreover, continues to extend its support for Docker V1 pulls, catering to users who might still rely on this earlier version of Docker images.

Support for OCI artifacts are enabled by default. The following examples show you how to use some media types, which can be used as examples for using other OCI media types.

Helm and OCI prerequisites

Before you use Helm charts with Project Quay, you can install a supported Helm client and trust registry certificates. OCI chart support requires a compatible Helm version.

Helm simplifies how applications are packaged and deployed. Helm uses a packaging format called Charts which contain the Kubernetes resources representing an application. supports Helm charts so long as they are a version supported by OCI.

You can download the most recent version of Helm from the Helm releases page.

Additional resources

Using Helm charts

To use Helm charts with Project Quay, you can push and pull OCI chart artifacts in the registry. You manage charts like other supported OCI media types.

Use the following example to download and push an etherpad chart from the Red Hat Community of Practice (CoP) repository.

Prerequisites
  • You have logged into Quay.

Procedure
  1. Add a chart repository by entering the following command:

    $ helm repo add redhat-cop https://redhat-cop.github.io/helm-charts
  2. Enter the following command to update the information of available charts locally from the chart repository:

    $ helm repo update
  3. Enter the following command to pull a chart from a repository:

    $ helm pull redhat-cop/etherpad --version=0.0.4 --untar
  4. Enter the following command to package the chart into a chart archive:

    $ helm package ./etherpad

    Example output

    Successfully packaged chart and saved it to: /home/user/linux-amd64/etherpad-0.0.4.tgz
  5. Log in to Project Quay using helm registry login:

    $ helm registry login quay370.apps.quayperf370.perfscale.devcluster.openshift.com
  6. Push the chart to your repository using the helm push command:

Annotation parsing

Some OCI media types do not include labels for metadata such as expiration. You can use ORAS annotations with Project Quay to embed that metadata in artifacts.

Tools such as ORAS (OCI Registry as Storage) can now be used to embed information with artifact types to help ensure that images operate properly, for example, to expire.

The following procedure uses ORAS to add an expiration date to an OCI media artifact.

Important

If you pushed an image with podman push, and then add an annotation with oras, the MIME type is changed. Consequently, you will not be able to pull the same image with podman pull because Podman does not recognize that MIME type.

Prerequisites
  • You have downloaded the oras CLI.

  • You have pushed an OCI media artifact to your Project Quay repository.

Procedure
  • By default, some OCI media types, like application/vnd.oci.image.manifest.v1+json, do not use certain labels, like expiration timestamps. You can use a CLI tool like ORAS (oras) to add annotations to OCI media types. For example:

    $ oras push --annotation "quay.expires-after=2d" \
    --annotation "expiration = 2d" \
    quay.io/<organization_name>/<repository>/<image_name>:<tag>

    where:

    --annotation "quay.expires-after=2d"

    Specifies that the expiration time is set for 2 days, indicated by 2d.

    --annotation "expiration = 2d"

    Specifies that the expiration label is added.

    Example output
    ✓ Exists    application/vnd.oci.empty.v1+json                                                                                   2/2  B 100.00%     0s
      └─ sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
    ✓ Uploaded  application/vnd.oci.image.manifest.v1+json                                                                      561/561  B 100.00%  511ms
      └─ sha256:9b4f2d43b62534423894d077f0ff0e9e496540ec8b52b568ea8b757fc9e7996b
    Pushed [registry] quay.io/stevsmit/testorg3/oci-image:v1
    ArtifactType: application/vnd.unknown.artifact.v1
    Digest: sha256:9b4f2d43b62534423894d077f0ff0e9e496540ec8b52b568ea8b757fc9e7996b
Verification
  1. Pull the image with oras. For example:

    $ oras pull quay.io/<organization_name>/<repository>/<image_name>:<tag>
  2. Inspect the changes using oras. For example:

    $ oras manifest fetch quay.io/<organization_name>/<repository>/<image_name>:<tag>
    Example output
    {"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.unknown.artifact.v1","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2,"data":"e30="},"layers":[{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2,"data":"e30="}],"annotations":{"org.opencontainers.image.created":"2024-07-11T15:22:42Z","version ":" 8.11"}}

Attaching referrers to an image tag

To attach referrers to an image tag in Project Quay, you can use the oras CLI with OCI distribution spec 1.1 referrers schemas.

This procedure shows you how to attach referrers to an image tag using different schemas supported by the OCI distribution spec 1.1 using the oras CLI. This is useful for attaching and managing additional metadata like referrers to container images.

Prerequisites
  • You have downloaded the oras CLI.

  • You have access to an OCI media artifact.

Procedure
  1. Tag an OCI media artifact by entering the following command:

    $ podman tag <myartifact_image> <quay-server.example.com>/<organization_name>/<repository>/<image_name>:<tag>
  2. Push the artifact to your Project Quay registry. For example:

    $ podman push <myartifact_image> <quay-server.example.com>/<organization_name>/<repository>/<image_name>:<tag>
  3. Enter the following command to attach a manifest using the OCI 1.1 referrers API schema with oras:

    $ oras attach --artifact-type <MIME_type> --distribution-spec v1.1-referrers-api <myartifact_image> \
    <quay-server.example.com>/<organization_name>/<repository>/<image_name>:<tag> \
    <example_file>.txt
    Example output
    -spec v1.1-referrers-api quay.io/testorg3/myartifact-image:v1.0 hi.txt
    ✓ Exists    hi.txt                                                               3/3  B 100.00%     0s
      └─ sha256:98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4
    ✓ Exists    application/vnd.oci.empty.v1+json                                    2/2  B 100.00%     0s
      └─ sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
    ✓ Uploaded  application/vnd.oci.image.manifest.v1+json                       723/723  B 100.00%  677ms
      └─ sha256:31c38e6adcc59a3cfbd2ef971792aaf124cbde8118e25133e9f9c9c4cd1d00c6
    Attached to [registry] quay.io/testorg3/myartifact-image@sha256:db440c57edfad40c682f9186ab1c1075707ce7a6fdda24a89cb8c10eaad424da
    Digest: sha256:31c38e6adcc59a3cfbd2ef971792aaf124cbde8118e25133e9f9c9c4cd1d00c6
  4. Enter the following command to attach a manifest using the OCI 1.1 referrers tag schema:

    $ oras attach --artifact-type <MIME_type> --distribution-spec v1.1-referrers-tag \
    <myartifact_image> <quay-server.example.com>/<organization_name>/<repository>/<image_name>:<tag> \
    <example_file>.txt
    Example output
    ✓ Exists    hi.txt                                                             3/3  B 100.00%     0s
      └─ sha256:98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4
    ✓ Exists    application/vnd.oci.empty.v1+json                                  2/2  B 100.00%     0s
      └─ sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
    ✓ Uploaded  application/vnd.oci.image.manifest.v1+json                     723/723  B 100.00%  465ms
      └─ sha256:2d4b54201c8b134711ab051389f5ba24c75c2e6b0f0ff157fce8ffdfe104f383
    Attached to [registry] quay.io/testorg3/myartifact-image@sha256:db440c57edfad40c682f9186ab1c1075707ce7a6fdda24a89cb8c10eaad424da
    Digest: sha256:2d4b54201c8b134711ab051389f5ba24c75c2e6b0f0ff157fce8ffdfe104f383
  5. Enter the following command to discoverer referrers of the artifact using the tag schema:

    $ oras discover --insecure --distribution-spec v1.1-referrers-tag \
    <quay-server.example.com>/<organization_name>/<repository>/<image_name>:<tag>
    Example output
    quay.io/testorg3/myartifact-image@sha256:db440c57edfad40c682f9186ab1c1075707ce7a6fdda24a89cb8c10eaad424da
    └── doc/example
        └── sha256:2d4b54201c8b134711ab051389f5ba24c75c2e6b0f0ff157fce8ffdfe104f383
  6. Enter the following command to discoverer referrers of the artifact using the API schema:

    $ oras discover --distribution-spec v1.1-referrers-api \
    <quay-server.example.com>/<organization_name>/<repository>/<image_name>:<tag>
    Example output
    Discovered 3 artifacts referencing v1.0
    Digest: sha256:db440c57edfad40c682f9186ab1c1075707ce7a6fdda24a89cb8c10eaad424da
    
    Artifact Type   Digest
                    sha256:2d4b54201c8b134711ab051389f5ba24c75c2e6b0f0ff157fce8ffdfe104f383
                    sha256:22b7e167793808f83db66f7d35fbe0088b34560f34f8ead36019a4cc48fd346b
                    sha256:bb2b7e7c3a58fd9ba60349473b3a746f9fe78995a88cb329fc2fd1fd892ea4e4
  7. Optional. You can also discover referrers by using the /v2/<organization_name>/<repository_name>/referrers/<sha256_digest> endpoint. For this to work, you must generate a v2 API token and set FEATURE_REFERRERS_API: true in your config.yaml file.

    1. Update your config.yaml file to include the FEATURE_REFERRERS_API field. For example:

      # ...
      FEATURE_REFERRERS_API: true
      # ...
    2. Enter the following command to Base64 encode your credentials:

      $ echo -n '<username>:<password>' | base64
      Example output
      abcdeWFkbWluOjE5ODlraWROZXQxIQ==
    3. Enter the following command to use the base64 encoded token and modify the URL endpoint to your Project Quay server:

      $ curl --location '<quay-server.example.com>/v2/auth?service=<quay-server.example.com>&scope=repository:quay/listocireferrs:pull,push' --header 'Authorization: Basic <base64_username:password_encode_token>' -k | jq
      Example output
      {
        "token": "<example_token_output>..."
      }
  8. Enter the following command, using the v2 API token, to list OCI referrers of a manifest under a repository:

    $ GET https://<quay-server.example.com>/v2/<organization_name>/<repository_name>/referrers/sha256:0de63ba2d98ab328218a1b6373def69ec0d0e7535866f50589111285f2bf3fb8
    --header 'Authorization: Bearer <v2_bearer_token> -k | jq
    Example output
    {
      "schemaVersion": 2,
      "mediaType": "application/vnd.oci.image.index.v1+json",
      "manifests": [
        {
          "mediaType": "application/vnd.oci.image.manifest.v1+json",
          "digest": "sha256:2d4b54201c8b134711ab051389f5ba24c75c2e6b0f0ff157fce8ffdfe104f383",
          "size": 793
        },
      ]
    }

Cosign OCI support

To sign and verify container images with Cosign in Project Quay, you can install Cosign and authenticate to the registry. Cosign uses ECDSA-P256 signatures and Simple Signing payloads.

Cosign is a tool that can be used to sign and verify container images. It uses the ECDSA-P256 signature algorithm and Red Hat’s Simple Signing payload format to create public keys that are stored in PKIX files. Private keys are stored as encrypted PEM files.

Cosign currently supports the following:

  • Hardware and KMS Signing

  • Bring-your-own PKI

  • OIDC PKI

  • Built-in binary transparency and timestamping service

Use the following procedure to directly install Cosign.

Prerequisites
  • You have installed Go version 1.16 or later.

Procedure
  1. Enter the following go command to directly install Cosign:

    $ go install github.com/sigstore/cosign/cmd/cosign@v1.0.0
    Example output
    go: downloading github.com/sigstore/cosign v1.0.0
    go: downloading github.com/peterbourgon/ff/v3 v3.1.0
  2. Generate a key-value pair for Cosign by entering the following command:

    $ cosign generate-key-pair
    Example output
    Enter password for private key:
    Enter again:
    Private key written to cosign.key
    Public key written to cosign.pub
  3. Sign the key-value pair by entering the following command:

    $ cosign sign -key cosign.key <quay-server.example.com>/user1/busybox:test
    Example output
    Enter password for private key:
    Pushing signature to: quay-server.example.com/user1/busybox:sha256-ff13b8f6f289b92ec2913fa57c5dd0a874c3a7f8f149aabee50e3d01546473e3.sig

    If you experience an UNAUTHORIZED: access to the requested resource is not authorized error when signing, which occurs because Cosign relies on ~./docker/config.json for authorization, you might need to execute the following command:

    $ podman login --authfile ~/.docker/config.json <_quay-server.example.com_or_quay.io_>
    Example output
    Username:
    Password:
    Login Succeeded!
  4. Enter the following command to see the updated authorization configuration:

    $ cat ~/.docker/config.json
    {
    	"auths": {
    		"quay-server.example.com": {
    			"auth": "cXVheWFkbWluOnBhc3N3b3Jk"
    		}
    	}

Installing and using Cosign

To install Cosign and sign images in Project Quay, you can generate a key pair, sign a tag, and verify the signature. You authenticate to the registry with your existing credentials.

Prerequisites
  • You have installed Go version 1.16 or later.

  • You have set FEATURE_GENERAL_OCI_SUPPORT to True in your config.yaml file.

Procedure
  1. Enter the following go command to directly install Cosign:

    $ go install github.com/sigstore/cosign/cmd/cosign@v1.0.0
    Example output
    go: downloading github.com/sigstore/cosign v1.0.0
    go: downloading github.com/peterbourgon/ff/v3 v3.1.0
  2. Generate a key-value pair for Cosign by entering the following command:

    $ cosign generate-key-pair
    Example output
    Enter password for private key:
    Enter again:
    Private key written to cosign.key
    Public key written to cosign.pub
  3. Sign the key-value pair by entering the following command:

    $ cosign sign -key cosign.key <quay-server.example.com>/user1/busybox:test
    Example output
    Enter password for private key:
    Pushing signature to: quay-server.example.com/user1/busybox:sha256-ff13b8f6f289b92ec2913fa57c5dd0a874c3a7f8f149aabee50e3d01546473e3.sig

    If you experience an UNAUTHORIZED: access to the requested resource is not authorized error when signing, which occurs because Cosign relies on ~./docker/config.json for authorization, you might need to execute the following command:

    $ podman login --authfile ~/.docker/config.json <quay-server.example.com>
    Example output
    Username:
    Password:
    Login Succeeded!
  4. Enter the following command to see the updated authorization configuration:

    $ cat ~/.docker/config.json
    {
    	"auths": {
    		"quay-server.example.com": {
    			"auth": "cXVheWFkbWluOnBhc3N3b3Jk"
    		}
    	}