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:
userstarts withocid1.user, andtenancystarts withocid1.tenancy. A compartment OCID intenancyis 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
rootor 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:
- The output of that command.
- The
fingerprintline in the config file. - 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
--profileexplicitly in scripts, so they don't depend on the environment of whoever runs them.