Rover API Key Commands

Create and manage API keys and client-credential pairs for your organization


Rover helps you manage credentials for your GraphOS organization with the rover api-key set of commands. It supports three types:

  • operator and subgraph API keys, which authenticate with GraphOS and determine permissions for accessing graphs, subgraphs, and other resources for your organization.

  • client-credentials pairs: an OAuth 2.0 client ID and secret, scoped to specific graphs. A pair is meant for CI and other automation, where Rover exchanges it for a short-lived access token instead of a long-lived API key.

note
Managing client-credential pairs requires the organization admin role.

Creating API keys and client-credential pairs

api-key create

The api-key create command creates a new API key or client-credential pair for your organization:

Text
1rover api-key create <ORGANIZATION_ID> <TYPE> <NAME>

The available types are:

  • operator: Full access to the organization

  • subgraph: Limited access to specific subgraphs

  • client-credentials: An OAuth 2.0 client-credential pair, limited to specific graphs

Subgraph keys

For subgraph keys, you can specify which subgraphs the key should have access to using a configuration file:

Text
1rover api-key create <ORGANIZATION_ID> subgraph <KEY_NAME> --subgraph-config subgraph-config.yaml

The subgraph configuration file should be in YAML format:

YAML
1graph-id:
2  variant-name:
3    - subgraph-name-1
4    - subgraph-name-2

You can also pipe the subgraph configuration from stdin:

Text
1cat subgraph-config.yaml | rover api-key create <ORGANIZATION_ID> subgraph <KEY_NAME>

Client-credential pairs

Provide at least one --graph-id to name a graph the client-credential pair may act on. Repeat the flag to give it access to more than one graph:

Text
1rover api-key create <ORGANIZATION_ID> client-credentials <NAME> --graph-id <GRAPH_ID> [--graph-id <GRAPH_ID>...] [--secret-lifetime-days <DAYS>]

--secret-lifetime-days sets how long the secret stays valid. If you omit it, GraphOS uses its own default.

Rover prints the new pair's client ID and secret to stdout, so CI setup can capture them, along with its name, graphs, and when the secret expires:

terminal
┌───────────────────┬──────────────────────┐
│ Client ID         ┆ c_8f2a               │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Client Secret     ┆ s_super-secret       │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Name              ┆ ci-deploy            │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Graphs            ┆ inventory, checkout  │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Secret Expires At ┆ 2028-09-25T16:00:00Z │
└───────────────────┴──────────────────────┘

On stderr, Rover adds a reminder:

terminal
Save this secret now. Rover can't show it again.

With --format json, the same values are reported in the data object. id repeats client_id, and scopes lists the scopes the pair holds:

JSON
1{
2  "json_version": "1",
3  "data": {
4    "key_type": "ClientCredentials",
5    "id": "c_8f2a",
6    "client_id": "c_8f2a",
7    "client_secret": "s_super-secret",
8    "secret_expires_at": "2028-09-25T16:00:00Z",
9    "name": "ci-deploy",
10    "graphs": [
11      "inventory",
12      "checkout"
13    ],
14    "scopes": [
15      "rover:cli"
16    ],
17    "success": true
18  },
19  "error": null
20}
caution
Rover shows the secret only once, when it's created. Save it somewhere secure immediately. If you lose it, rotate the pair to get a new one.

To authenticate Rover with a pair, set these two environment variables instead of APOLLO_KEY:

Text
1APOLLO_CLIENT_ID=<CLIENT_ID>
2APOLLO_CLIENT_SECRET=<CLIENT_SECRET>
caution
If APOLLO_KEY is also set, it takes precedence.

Example: setting up CI with a pair

  1. As an organization admin, create a pair for the graph your pipeline publishes to, and capture its credentials from the JSON output:

    Bash
    1rover api-key create <ORGANIZATION_ID> client-credentials ci-deploy \
    2  --graph-id <GRAPH_ID> --format json > pair.json
    3jq -r .data.client_id pair.json
    4jq -r .data.client_secret pair.json
  2. Store the two values as secrets in your CI provider, for example as APOLLO_CLIENT_ID and APOLLO_CLIENT_SECRET, then delete pair.json.

  3. Expose them to Rover as environment variables in your pipeline. In GitHub Actions:

    YAML
    1- name: Publish subgraph
    2  env:
    3    APOLLO_CLIENT_ID: ${{ secrets.APOLLO_CLIENT_ID }}
    4    APOLLO_CLIENT_SECRET: ${{ secrets.APOLLO_CLIENT_SECRET }}
    5  run: rover subgraph publish <GRAPH_REF> --name products --schema ./products.graphql

When it's time to replace the secret, rotate the pair with a grace period and update the CI secret. The previous secret keeps working until the grace period ends.

Listing API keys and client-credential pairs

api-key list

The api-key list command lists your organization's API keys and client-credential pairs:

Text
1rover api-key list <ORGANIZATION_ID> [--type <TYPE>...] [--limit <N>] [--after <CURSOR>]

Rover shows API keys with their ID, name, creation date, and expiration date (if any). Client-credential pairs follow, in a separate Client-credential pairs table, with their name, client ID, graphs, creation date, and who created them. Secrets are never shown.

Use --type to list only certain types. Pass operator, subgraph, or client-credentials. You can repeat this flag:

Text
1rover api-key list <ORGANIZATION_ID> --type client-credentials

With --format json, the command reports API keys in a keys array and pairs in a client_credentials array. The output omits types excluded by --type entirely, rather than reporting them as an empty array.

note
If you don't have permission to see your organization's client-credential pairs, or it isn't enrolled in client-credential support, api-key list shows its API keys and no pairs, the same as for an organization with no pairs at all.

If Rover can't fetch the pairs, for example because the request timed out or GraphOS returned a server error, the command fails with error E056. Any API keys in scope were already fetched and are still shown. Run the command again. If the problem persists, check the Platform API's status.

Paging through client-credential pairs

api-key list collects at most 100 pairs per run by default. Use --limit to change that. It must be a positive whole number. If your organization has more pairs than the limit, the command still succeeds and prints a note naming a cursor. Pass that cursor to --after to continue where the last run stopped:

Text
1rover api-key list <ORGANIZATION_ID> --type client-credentials --limit 50 --after <CURSOR>

With --format json, the output reports the cursor as client_credentials_next_after. It's null once every pair has been listed, as in this output:

JSON
1{
2  "json_version": "1",
3  "data": {
4    "keys": [
5      {
6        "created_at": "2026-01-04T12:00:00Z",
7        "expires_at": null,
8        "id": "key-123",
9        "name": "router-prod",
10        "key_type": "Operator"
11      }
12    ],
13    "client_credentials": [
14      {
15        "key_type": "ClientCredentials",
16        "id": "c_8f2a",
17        "client_id": "c_8f2a",
18        "name": "ci-deploy",
19        "graphs": [
20          "inventory"
21        ],
22        "scopes": [
23          "rover:cli"
24        ],
25        "created_at": "2026-09-25T16:00:00Z",
26        "created_by": {
27          "id": "user-123",
28          "type": "user"
29        }
30      }
31    ],
32    "client_credentials_next_after": null,
33    "success": true
34  },
35  "error": null
36}

When more pairs remain, the text output ends with a note, and client_credentials_next_after holds the same cursor in place of null:

terminal
More client-credential pairs are available. Resume with `--after <CURSOR>`.

--limit and --after apply only to client-credential pairs. API keys are always listed in full.

Rotating client-credential pairs

api-key rotate

The api-key rotate command creates a new secret for a client-credential pair:

Text
1rover api-key rotate <ORGANIZATION_ID> <CLIENT_ID> [--grace-period-days <DAYS>]

By default, every previous secret for the pair stops working immediately. To roll out the new secret without downtime, pass --grace-period-days to keep the previous secrets working for that many days.

Rover prints the pair's client ID, the new secret, and the secret's expiration to stdout. As with creating a pair, Rover shows the new secret only once. On stderr, it reminds you to save the secret and says when the previous secrets stop working. Without a grace period:

Text
1Save this secret now. Rover can't show it again.
2Every previous secret for `<NAME>` has stopped working. To keep the old secret working while you roll out a new one, pass `--grace-period-days <DAYS>`.

With a grace period, the second line is instead:

Text
1Every previous secret for `<NAME>` keeps working until <TIMESTAMP>.

<NAME> is the pair's name, or its client ID if it has none.

The stdout text output is:

terminal
┌───────────────────┬──────────────────────┐
│ Client ID         ┆ c_8f2a               │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Client Secret     ┆ s_new-secret         │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ Secret Expires At ┆ 2028-09-25T16:00:00Z │
└───────────────────┴──────────────────────┘

With --format json, the output is:

JSON
1{
2  "json_version": "1",
3  "data": {
4    "key_type": "ClientCredentials",
5    "id": "c_8f2a",
6    "client_id": "c_8f2a",
7    "client_secret": "s_new-secret",
8    "secret_expires_at": "2028-09-25T16:00:00Z",
9    "grace_period_days": 1,
10    "previous_secrets_expire_at": "2026-09-25T16:00:00Z",
11    "success": true
12  },
13  "error": null
14}

grace_period_days and previous_secrets_expire_at describe the grace period you passed.

If the request fails in a way that leaves the outcome unclear, such as a timeout, Rover can't tell whether the secret was rotated and suggests checking with rover api-key list <ORGANIZATION_ID>. It never prints a secret in that case.

api-key rotate works on client-credential pairs only. If the ID isn't a pair in the organization, the command fails with error E057 and changes nothing.

Deleting API keys and client-credential pairs

api-key delete

The api-key delete command deletes an API key or a client-credential pair:

Text
1rover api-key delete <ORGANIZATION_ID> <ID>

<ID> can be an API key's ID or a pair's client ID. Rover determines which it is.

When you delete a pair, it can no longer obtain new access tokens. Access tokens it already holds keep working until they expire, for up to 15 minutes.

caution
This action can't be undone. Make sure you have the correct ID before deleting.

Renaming API keys

api-key rename

The api-key rename command renames an existing API key:

Text
1rover api-key rename <ORGANIZATION_ID> <KEY_ID> <NEW_KEY_NAME>

Use this command to organize and identify your API keys more easily.

You can't rename client-credential pairs. If you provide a pair's client ID, the command fails with error E059 and changes nothing. To give a pair a different name, create a new pair and delete the old one.