Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Terraform By James Joyner IV · · 9 min read

Terraform Error Guide: 'authentication failed' — provider credentials for AWS, Azure, GCP

Fix Terraform provider authentication errors: refresh expired SSO/STS tokens, set AWS/ARM/GOOGLE env vars, pick the right profile, and repair assume-role and OIDC in CI.

  • #terraform
  • #troubleshooting
  • #errors
  • #auth

Exact Error Message

These are the provider-credential variants users paste into Google. Note: this guide covers cloud/provider authentication, not state-backend access — for that see Related Errors.

Error: No valid credential sources found

  with provider["registry.terraform.io/hashicorp/aws"],
  on main.tf line 2, in provider "aws":
   2: provider "aws" {

Please see https://registry.terraform.io/providers/hashicorp/aws
for more information about providing credentials.
Error: building AzureRM Client: obtain subscription() from Azure CLI: ...
Azure CLI Authorization Profile was not found. Please ensure the Azure CLI is
installed and then log-in with `az login`.

Error: Attempted to load application default credentials since neither
`credentials` nor `access_token` was set in the provider block. No credentials
loaded. To use your gcloud credentials, run 'gcloud auth application-default login'.
google: could not find default credentials.

What the Error Means

Terraform providers authenticate to the cloud API the same way the cloud’s own CLI does — through a chain of credential sources (environment variables, shared profiles, instance/workload identity, CLI sessions). “Authentication failed” / “No valid credential sources found” means Terraform walked that entire chain and either found nothing usable or found credentials the cloud rejected (expired, wrong account, insufficient identity).

Crucially, this happens during the provider configuration / API call stage, before Terraform touches any resource. It is distinct from a failure to read remote state — the state backend has its own credential resolution. If your error mentions a bucket, dynamodb, or “loading state,” see Failed to load state instead. This guide is about the credentials your provider "aws"/"azurerm"/"google" block uses.

Common Causes

  • Missing or expired environment variablesAWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN, ARM_CLIENT_ID/ARM_CLIENT_SECRET/ARM_TENANT_ID/ARM_SUBSCRIPTION_ID, or GOOGLE_APPLICATION_CREDENTIALS.
  • Expired SSO / STS / CLI sessionaws sso login, az login, or gcloud auth token timed out; STS session tokens are short-lived.
  • Wrong profileAWS_PROFILE (or profile in the block) points at an unconfigured or different-account profile.
  • Assume-role / OIDC misconfig in CI — the workflow’s federated identity is not trusted by the role, the audience/subject claim is wrong, or role_to_assume is mistyped.
  • Clock skew — request signatures fail when the machine’s clock drifts more than a few minutes (SignatureDoesNotMatch).
  • MFA required — the role or account demands MFA the current session does not carry.

How to Reproduce the Error

Unset the credentials and run a plan against a provider that has no other source:

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_PROFILE
terraform plan
Error: No valid credential sources found

Or let an SSO session expire (or revoke it) and re-run:

aws sso logout
terraform plan
Error: failed to refresh cached SSO token: the SSO session has expired or is invalid

Diagnostic Commands

Always confirm who the cloud thinks you are with the native CLI before blaming Terraform:

# AWS — the single most useful check
aws sts get-caller-identity
echo "$AWS_PROFILE"; aws configure list

# Azure
az account show --output table
az account get-access-token >/dev/null && echo "token ok"

# GCP
gcloud auth list
gcloud auth application-default print-access-token >/dev/null && echo "ADC ok"
echo "$GOOGLE_APPLICATION_CREDENTIALS"

Turn on Terraform’s provider trace to see exactly which credential source it tried and how the API rejected it:

TF_LOG=DEBUG terraform plan 2>&1 | grep -i 'credential\|auth\|sts\|token\|403\|expired'

Step-by-Step Resolution

AWS

  1. Refresh the session. For SSO/Identity Center, re-login; for raw keys, re-export.

    aws sso login --profile prod
    export AWS_PROFILE=prod
    aws sts get-caller-identity        # must succeed before terraform
  2. Set explicit keys only if you must (prefer profiles/SSO):

    export AWS_ACCESS_KEY_ID=AKIA...
    export AWS_SECRET_ACCESS_KEY=...
    export AWS_SESSION_TOKEN=...        # required for temporary/STS creds
  3. Fix assume-role in the provider block — make sure the source identity is allowed to assume the role:

    provider "aws" {
      region = "us-east-1"
      assume_role {
        role_arn     = "arn:aws:iam::111122223333:role/terraform"
        session_name = "terraform-ci"
      }
    }
    # Verify the assume-role works outside Terraform
    aws sts assume-role --role-arn arn:aws:iam::111122223333:role/terraform \
      --role-session-name test

Azure

  1. Interactive: az login then select the subscription.

    az login
    az account set --subscription "<SUB_ID>"
    az account show -o table
  2. Service principal (CI): export all four ARM_ vars.

    export ARM_CLIENT_ID=...
    export ARM_CLIENT_SECRET=...
    export ARM_TENANT_ID=...
    export ARM_SUBSCRIPTION_ID=...
    provider "azurerm" {
      features {}
      # use_oidc = true   # for federated CI instead of a secret
    }

GCP

  1. Application Default Credentials for local dev:

    gcloud auth application-default login
    gcloud config set project my-project
  2. Service-account key file (or workload identity in CI):

    export GOOGLE_APPLICATION_CREDENTIALS=/secure/sa-terraform.json
    gcloud auth application-default print-access-token >/dev/null

Cross-cloud fixes

  • Clock skew: sudo chronyc makestep (or enable NTP) if you see SignatureDoesNotMatch/RequestTimeTooSkewed.
  • OIDC in CI: confirm the role/identity trust policy lists the exact aud/sub claim for your runner, and that the CI step actually requests the token (id-token: write in GitHub Actions).

Verify

terraform plan

A plan that reads resources without an auth error confirms the credentials resolved.

Prevention and Best Practices

  • Prefer short-lived federated credentials (AWS SSO/OIDC, Azure workload identity, GCP workload identity federation) over long-lived static keys.
  • Never commit keys or GOOGLE_APPLICATION_CREDENTIALS files; inject them at runtime from a secrets manager.
  • Make aws sts get-caller-identity / az account show / gcloud auth list the first step of every runbook and CI job — fail fast with a clear message.
  • Pin the profile/subscription/project explicitly in CI env so a developer’s local default never leaks in.
  • Keep machine clocks NTP-synced to avoid signature errors.
  • The free incident assistant can read a TF_LOG trace and name the failing credential source. More patterns in the Terraform guides.
  • Failed to load state — when the state backend (S3/GCS/Blob) rejects credentials or the object is missing, which is a separate credential chain from the provider covered here.
  • Backend configuration changed — when re-init reaches the backend but the backend block itself changed.
  • Error: error configuring S3 Backend: no valid credential sources — looks identical but applies to the backend, not the provider; resolve via backend credentials.
  • SignatureDoesNotMatch / RequestTimeTooSkewed — the clock-skew sub-case of provider auth.

Frequently Asked Questions

Why does aws sts get-caller-identity work but Terraform still fails? Terraform may be resolving a different source than your shell test — for example a profile/assume_role in the provider block, or a stale AWS_PROFILE exported in CI. Run TF_LOG=DEBUG terraform plan and grep for credential to see which source it actually used.

How is this different from a state-backend authentication error? Provider credentials authenticate the API calls that create/read resources; the backend has its own, separate credential resolution for reading state. A backend failure mentions a bucket, dynamodb, or “loading state” — see Failed to load state. This guide covers the provider {} block.

My CI worked yesterday and now says “No valid credential sources.” Almost always an expired short-lived token (SSO/STS/OIDC) or a rotated secret. Re-login locally (aws sso login, az login), and in CI confirm the OIDC step still requests a token and the role trust policy matches the runner’s claims.

Do I need AWS_SESSION_TOKEN? Yes, whenever your credentials are temporary (SSO, STS assume-role, IAM Identity Center). Long-lived IAM user keys do not use it, but omitting it for temporary creds yields InvalidClientTokenId/auth failures.

Could a clock problem really cause this? Yes. AWS and Azure reject signed requests when the clock drifts past a tolerance window, surfacing as SignatureDoesNotMatch or RequestTimeTooSkewed. Sync time with NTP/chrony, especially on long-running or sleeping laptops and freshly booted CI runners.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.