Using Authentication
How to log in, make authenticated API calls, manage tokens, and create Scoped Access Keys with the CLI and SDK.
Prerequisites: For OIDC login, configure an identity provider first. See OIDC. For local testing without OIDC, use nemo auth login --unsigned-token --email <email>. Scoped Access Keys also require the administrator to enable auth.access_keys.enabled; see Authentication Configuration.
Log In
The device flow is the recommended login method. It opens your browser to authenticate with your organization’s identity provider.
Expected output:
Open the URL, enter the code, and sign in with your IdP credentials. After consent, verify:
All CLI and SDK commands now use the stored token automatically.
Requesting Specific Scopes
By default, the CLI requests the scopes configured in auth.oidc.default_scopes (typically platform:read platform:write plus OIDC standard scopes like openid profile email offline_access). Restrict the token’s access by specifying fewer scopes:
See API Scopes for the full list of available scopes.
Non-Interactive Login (CI/CD)
For CI pipelines, use the password grant to obtain a token without a browser: nemo auth login --username <user> --password <pass> (or set NMP_OIDC_USERNAME / NMP_OIDC_PASSWORD environment variables). If your CI system can obtain tokens directly (e.g., workload identity federation), pass the token via access_token as shown in Make API Calls below.
Password grant sends credentials directly to the IdP and bypasses MFA. Many production IdPs disable it. Use a dedicated service account with minimal scopes where possible.
Make API Calls
Python SDK
The SDK reads credentials from the CLI config automatically — no manual token handling needed:
If you need explicit token control (for example, a token from a CI system or environment variable), pass it via access_token:
HTTP (curl)
Scoped Access Keys for Non-SDK Clients
When Scoped Access Keys are enabled by the platform administrator, an authenticated user can mint a scoped bearer token for automation that cannot use the SDK’s OIDC refresh flow:
Scoped Access Key management commands live under the auth namespace as
nemo auth access-keys .... The access-keys command group is not a top-level CLI
command and is not a separate NeMo Platform plugin.
create prints the Scoped Access Key token once. Store it in your secret
manager and send it in the standard Authorization header:
Scoped Access Keys are signed JWT bearer tokens scoped to the principal and
groups present when the key is created. By default, new keys use the platform’s
configured default expiry, which is 30 days unless the administrator changes it.
Pass --expires-in <seconds> to request a specific finite lifetime. Pass
--expires-in none only for deployments where the administrator has explicitly
allowed unlimited keys.
Restrict a key to specific services with --scope, and grant its principal
workspace membership with --workspace (formatted <workspace> or
<workspace>:<role1>,<role2>, repeatable) instead of a separate
nemo workspaces members create call. Creating a service-bound key with
--service-account requires the PlatformAdmin role; omit it to create a
personal, user-bound key instead:
A --scope-restricted key is enforced platform-wide, not just advisory: it can only
call endpoints whose required scope is covered by the services you listed (plus any
platform:read/platform:write-scoped endpoint). This includes the access-key
management endpoints themselves — a key scoped to intake,entities cannot create,
list, suspend, unsuspend, rotate, or revoke access keys unless --scope also includes
auth, which prevents a restricted key from minting itself broader access. This
applies even to a PlatformAdmin’s own scoped key: the PlatformAdmin bypass only
grants access within the key’s own scope, so a PlatformAdmin who scopes down their
own key is still restricted by it, not granted unconditional access.
Rotate a personal key (one created without --service-account) by passing
--rotate <jti> with the prior key’s jti: once the replacement key is
created and its requested workspace grants are provisioned, the referenced key
is revoked. --rotate only accepts a key you own that has no service account
bound to it.
List keys, temporarily suspend and restore one, rotate one, or permanently revoke one by
its stable jti:
The list includes each key’s ACTIVE, EXPIRED, SUSPENDED, ROTATING, or REVOKED
status plus its description, issuer, audiences, creation time, expiration time, and last
authentication time. Suspension and revocation take effect on subsequent authenticated
platform requests. Use suspension to temporarily block a key, such as while investigating
suspected misuse, without permanently revoking it. An unexpired suspended key can be
restored with unsuspend. If the key expires while suspended, unsuspend is a no-op and
reports EXPIRED. A revoked key cannot be restored.
rotate mints a successor key with the same name, description, and lifetime
characteristics, prints its token once, and transitions the original key to ROTATING.
The rotated-out key keeps authenticating for a dual-active grace period (configurable via
auth.access_keys.rotation_grace_period_seconds, 48 hours by default) so you can update
configuration or secret stores to the new key without downtime, then call revoke on the
old jti once traffic has moved over — check its last authentication time in list to
confirm no recent traffic before revoking. If you don’t revoke it manually, it is treated
as revoked automatically once the grace period elapses. A key must be ACTIVE to rotate;
a suspended, already-rotating, expired, or revoked key must be resolved first.
Token Inspection
Retrieve the raw JWT for debugging or use in other clients:
Decode the token to inspect claims:
Key claims to check:
emailorupn— the principal identityscporscope— granted scopesexp— expiry timestampiss— issuer URL (must match your config)aud— audience (must match your config)
Token Management
How Auto-Refresh Works
You never need to refresh tokens manually — the CLI and SDK handle it transparently:
- SDK: Refreshes lazily before each API call when the token is within 60 seconds of expiry. No background threads or timers — the cost is paid only when a refresh is actually needed (typically once per hour). Multiple
NeMoPlatform()clients in the same Python process share a single token, so only one refresh happens even with many clients. - CLI: Checks the token before every command and refreshes if it expires within 5 minutes. To disable for a specific command:
nemo --no-auto-refresh workspaces list.
Running multiple scripts or CLI commands simultaneously is safe — file-level locking prevents conflicts when refreshing tokens across processes.
If the refresh token itself has expired (e.g., after days of inactivity), re-login with nemo auth login.
Manual Refresh and Logout
Config File
Tokens are stored in ~/.config/nmp/config.yaml:
The OIDC token endpoint is not stored — it is discovered at runtime from your cluster’s /apis/auth/discovery endpoint. This keeps the config portable across environments.
Token storage security — Access and refresh tokens are stored in plaintext. Protect this file:
- File permissions: Ensure
0600(owner read/write only). The CLI sets this by default — verify after manual edits:chmod 600 ~/.config/nmp/config.yaml. - Shared directories: Do not store in cloud-synced folders (Dropbox, OneDrive, Google Drive) or shared home directories.
- Refresh token rotation: Configure your IdP to rotate refresh tokens on each use. A stolen refresh token becomes invalid after the legitimate client uses it once.
- Logout when done: Run
nemo auth logouton shared or temporary machines.
Related
- OIDC — Configure your identity provider.
- API Scopes — Scope model and available scopes.
- Security Model — Trust boundaries and the principal model.
- Troubleshooting — Fix common 401/403 errors and login failures.