Home / OCI

OCITroubleshootingBeginner

OCI CLI returns 401 NotAuthenticated: API key, fingerprint, clock and profile checks

OCI CLI, SDK or script calls fail with 401 NotAuthenticated. Work through the active profile, key pair, fingerprint, user state, clock and region to find the cause and fix it.

Deepak Bhardwaj7 min read

Applies toOCI CLI 3.x with API key or session token authentication; the same config file is used by the OCI SDKs

Symptom

An oci command, SDK call or script fails with status 401 and code NotAuthenticated. A 401 means OCI couldn't authenticate your request. Your policies usually aren't the first place to look.

Response What it means Look at
401 NotAuthenticated Credentials are missing, wrong or unusable This post
404 NotAuthorizedOrNotFound The resource doesn't exist or you have no access to it. OCI doesn't tell you which The OCID, compartment, region and IAM policies

Quick diagnosis

Finding Likely cause Go to
Works with --profile X, fails without it Wrong profile or an environment override Check 1
Fingerprint doesn't match the user's keys Wrong key, or the key was rotated or deleted Check 3
key_file starts with BEGIN PUBLIC KEY Config points to the public key Check 2
Local time differs from the server by over 5 minutes Clock skew Check 5
Works in the home region only Tenancy isn't subscribed to the target region Check 6
Worked for an hour, then stopped Session token expired Check 7

Use a simple test call throughout. It needs valid credentials and returns your Object Storage namespace:

oci os ns get

Check 1: which credentials is the CLI using?

Command options beat environment variables, and environment variables beat the config file. A leftover variable can override a correct config, so look for those first.

env | grep '^OCI_CLI_'

In PowerShell:

Get-ChildItem Env:OCI_CLI_*

Look for OCI_CLI_PROFILE, OCI_CLI_AUTH, OCI_CLI_CONFIG_FILE, OCI_CLI_USER, OCI_CLI_FINGERPRINT, OCI_CLI_KEY_FILE, OCI_CLI_TENANCY and OCI_CLI_REGION. Clear any that shouldn't be there:

unset OCI_CLI_AUTH OCI_CLI_PROFILE
oci os ns get --profile DEFAULT

Next, read the profile. It needs these entries for API key authentication:

[DEFAULT]
user=ocid1.user.oc1..xxxx
fingerprint=12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef
tenancy=ocid1.tenancy.oc1..xxxx
region=ap-mumbai-1
key_file=~/.oci/oci_api_key.pem

Check that:

  • user starts with ocid1.user, and tenancy starts with ocid1.tenancy. A compartment OCID in tenancy is a common copy-paste mistake.
  • The profile belongs to the tenancy you are calling, if you work with several.
  • The user running the command is the expected one. A job under root or a service account reads a different home directory, and so a different ~/.oci/config.

To see what is sent, add --debug:

oci os ns get --debug 2>&1 | less

Warning

Debug output contains request details such as your tenancy and user OCIDs and the key fingerprint. Remove them before you paste it into a ticket or chat.

Check 2: is key_file the private key?

head -1 ~/.oci/oci_api_key.pem
First line Meaning
-----BEGIN RSA PRIVATE KEY----- or -----BEGIN PRIVATE KEY----- Private key, correct
-----BEGIN ENCRYPTED PRIVATE KEY----- Encrypted private key. You need the passphrase
-----BEGIN PUBLIC KEY----- Public key, wrong. Point key_file to the private key
ssh-rsa ... or -----BEGIN OPENSSH PRIVATE KEY----- SSH format. API signing keys must be RSA in PEM format

If the CLI warns about loose file permissions, fix them. This command works on Windows too:

oci setup repair-file-permissions --file ~/.oci/oci_api_key.pem

Check 3: does the fingerprint match?

Work out the fingerprint from the private key:

openssl rsa -pubout -outform DER -in ~/.oci/oci_api_key.pem | openssl md5 -c

Then compare three values:

  1. The output of that command.
  2. The fingerprint line in the config file.
  3. The fingerprints uploaded for the user.

Your CLI can't authenticate yet, so run the last command from Cloud Shell or under another working profile. Viewing another user's keys requires the right IAM permissions.

oci iam user api-key list --user-id "$USER_OCID" \
  --query 'data[].{fingerprint:fingerprint,state:"lifecycle-state"}' --output table
Result Fix
Config differs from the key, and the key's fingerprint is on the user Correct the fingerprint line
Key's fingerprint isn't on the user Upload the public key, or use the private key that matches
Key is on a different user Correct the user line, or upload the key to this user

To upload the public key, derive it from the private key first:

openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem
oci iam user api-key upload --user-id "$USER_OCID" \
  --key-file ~/.oci/oci_api_key_public.pem

A user can have up to three API keys. If you have reached that limit, delete one that is no longer in use.

Caution

Deleting an API key breaks everything that signs with it, straight away. That can include Terraform, backup scripts and monitoring jobs. Confirm who uses a key before you run oci iam user api-key delete. If the key may have leaked, follow the credential leak response instead.

Check 4: is the user allowed to use API keys?

From Cloud Shell or another working profile:

oci iam user get --user-id "$USER_OCID" \
  --query 'data.{name:name,state:"lifecycle-state",capabilities:capabilities}'

Confirm that the user is ACTIVE and that can-use-api-keys is true. An administrator may have blocked or changed the account, or turned the capability off.

Oracle's API error reference also lists a user who isn't in a group with permission for the action as a possible cause of a 401. Check group membership if everything else on this page is correct:

oci iam user list-groups --user-id "$USER_OCID" --compartment-id "$TENANCY_OCID" --output table

Check 5: is the clock right?

OCI returns 401 when the client clock is more than 5 minutes from the server clock. Compare the two:

date -u
curl -s --head https://iaas.ap-mumbai-1.oraclecloud.com | grep -i '^date'

Replace the region in the URL with yours. If they differ by more than a minute or two, fix time sync, not the credentials. On Linux:

sudo systemctl restart chronyd
chronyc tracking

On Windows:

w32tm /resync
w32tm /query /status

For the permanent fix on OCI instances, see OCI instance clock drift and time sync.

Check 6: is the tenancy subscribed to the region?

A 401 can also mean that your tenancy isn't subscribed to the region you are calling.

oci iam region-subscription list --tenancy-id "$TENANCY_OCID" --output table

If the target region isn't listed or isn't READY, change region or --region, or have a tenancy administrator subscribe to it.

Check 7: session tokens and principals

If the profile uses security_token_file, the token expires.

oci session validate --profile MYPROFILE --auth security_token
oci session refresh --profile MYPROFILE --auth security_token

# If the session can't be refreshed, sign in again
oci session authenticate --profile-name MYPROFILE --region ap-mumbai-1

Tokens last up to 60 minutes and can be refreshed within their validity period, for up to 24 hours. After that, you must sign in again. Scripts and scheduled jobs shouldn't depend on a session token.

If the command needs --auth security_token, set that flag or OCI_CLI_AUTH=security_token. Without it, the CLI tries API key authentication with entries that the profile may not have.

On an OCI instance with OCI_CLI_AUTH=instance_principal, the config file isn't used for signing. Check the clock first. For dynamic group and policy problems, see the instance principal fixes.

Prevent it next time

  • Use instance principals for automation on OCI instances, so there are no key files to manage.
  • Add a one-line health check to scheduled jobs, such as oci os ns get --profile PROD, and alert when it fails.
  • Keep a record of each API key's owner, fingerprint and consumers, and rotate one consumer at a time.
  • When rotating, upload the new key first, switch the config, test, and only then delete the old key.
  • Set --profile explicitly in scripts, so they don't depend on the environment of whoever runs them.