AWS CLI / SDK aws credentials auth

AWS InvalidClientTokenId: The security token is invalid

Encountering InvalidClientTokenId means your AWS credentials are malformed, expired, or for the wrong region; this guide explains how to fix it.

What This Error Means

When you encounter the InvalidClientTokenId: The security token is invalid error, it signifies a fundamental problem with the AWS credentials your application or CLI is attempting to use. It's not a permissions issue; it means AWS cannot recognize or validate the identity you're presenting, let alone check what permissions that identity has. Think of it like trying to open a door with a key that's bent, broken, or simply not for this lock. The system can't even tell if you should have access because it can't verify who you are.

This error is typically reported directly by the AWS API endpoint you're trying to reach. Whether you're using the AWS Command Line Interface (CLI), an AWS SDK in your code (Python, Node.js, Java, etc.), or a tool that leverages these, if the credentials provided are malformed, expired, or otherwise invalid at the point of authentication, this error will be returned.

Why It Happens

The core reason this error occurs is that the AWS service you're interacting with has rejected the access key ID and/or secret access key you've provided. AWS uses these tokens to identify and authenticate your requests. If these tokens are incorrect, expired, or misconfigured, the authentication process fails immediately.

AWS has a sophisticated system for managing credentials, including long-term IAM user access keys and short-term security tokens generated by the AWS Security Token Service (STS) for temporary access (e.g., when assuming an IAM role, federated users, or using MFA). This error points to an issue with one of these components. In my experience, it often boils down to temporary credentials expiring unnoticed or a configuration mismatch.

Common Causes

Here's a breakdown of the most common scenarios that lead to InvalidClientTokenId:

  • Expired Temporary Credentials: This is, by far, the most frequent culprit. When you assume an IAM role (via aws sts assume-role), use MFA credentials, or use temporary credentials for federated access, these credentials have a limited lifespan (e.g., 1 hour, 6 hours, or up to 12 hours). If you try to use them after they've expired, you'll hit this error.
  • Incorrect AWS Region Configuration: AWS access keys are globally unique, but the session for temporary credentials can be region-specific in how they're generated or consumed. More commonly, if your client is configured for a region where your IAM user or role doesn't exist, or if you're trying to access a resource that only exists in a different region, the request might implicitly fail authentication if the service endpoint isn't correctly resolved or if the token itself was generated with a region constraint.
  • Malformed Access Keys or Secret Keys: Simple typos, leading/trailing whitespace, or copy-paste errors when setting AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or values in ~/.aws/credentials can easily lead to this error. The keys must be exactly as provided by AWS.
  • IAM User Access Key Deactivated or Deleted: If the IAM user associated with the access key has had their keys rotated, deactivated, or deleted, any active clients using those keys will start failing with this error.
  • Environment Variables Overriding Configuration: Credentials can be sourced from environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN), the shared ~/.aws/credentials file, or the ~/.aws/config file. If old or incorrect credentials are set as environment variables, they will often take precedence and cause the error, even if your configuration files are correct.
  • System Clock Skew: Although less common with modern operating systems, a significant difference between your local system's time and the AWS service's time can cause authentication failures. AWS uses timestamps in its request signing process.
  • Incorrect Profile Usage: If you have multiple profiles configured in your ~/.aws/credentials or ~/.aws/config files, and you're not explicitly specifying the correct profile (e.g., via --profile flag or AWS_PROFILE environment variable), your client might pick up the default profile, which could contain invalid or expired credentials.
  • Corrupted Credentials File: Rarely, the ~/.aws/credentials file itself might become corrupted, leading to parsing errors by the AWS CLI or SDKs.

Step-by-Step Fix

Let's systematically troubleshoot and resolve this error.

  1. Verify Your Current AWS Identity and Region:
    Start by checking what AWS credentials the CLI or SDK thinks it's using.
    bash aws sts get-caller-identity
    This command will show you the ARN of the IAM user or role you're currently authenticated as, along with your account ID and the user/session ID. If this command itself fails with InvalidClientTokenId, it confirms your default credentials are bad.
    Also check your configured region:
    bash aws configure get region
    Ensure this is the region you intend to operate in.

  2. Inspect Environment Variables:
    Environment variables take precedence. Check if any AWS credential variables are set.
    bash echo $AWS_ACCESS_KEY_ID echo $AWS_SECRET_ACCESS_KEY echo $AWS_SESSION_TOKEN echo $AWS_DEFAULT_REGION echo $AWS_REGION echo $AWS_PROFILE
    If any of these output unexpected or old values, they are likely the cause. You can unset them:
    bash unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY unset AWS_SESSION_TOKEN # Only unset AWS_DEFAULT_REGION/AWS_REGION if you want to rely on config files # unset AWS_DEFAULT_REGION # unset AWS_REGION unset AWS_PROFILE
    After unsetting, try aws sts get-caller-identity again.

  3. Check ~/.aws/credentials and ~/.aws/config:
    Open these files and inspect your profiles.

    • ~/.aws/credentials: Look for sections like [default] or [your-profile-name].
      ```ini
      [default]
      aws_access_key_id = AKIA...
      aws_secret_access_key = YOURSECRET...

      [dev-profile]
      aws_access_key_id = AKIA...
      aws_secret_access_key = YOURSECRET...
      aws_session_token = AFG... # if using temporary credentials
      * `~/.aws/config`:ini
      [default]
      region = us-east-1
      output = json

      [profile dev-profile]
      region = us-west-2
      output = json
      sso_session = my-sso
      sso_account_id = 123456789012
      sso_role_name = Developer

      ... or for role assumption

      role_arn = arn:aws:iam::123456789012:role/MyDevRole
      source_profile = base-profile-with-creds
      `` Ensure that: * Theaws_access_key_idandaws_secret_access_keyare correct and haven't expired (if they are IAM user keys). * Ifaws_session_tokenis present, it means you're using temporary credentials. These *will* expire. Ifget-caller-identityfails, this is almost certainly the issue. * Theregionconfigured matches where you intend to work. * If using named profiles, ensure you're explicitly calling them (e.g.,aws --profile dev-profile s3 ls`).

  4. Re-authenticate Temporary Credentials (MFA/Role Assumption):
    If you're using temporary credentials (e.g., for MFA or an assumed role), they've likely expired. You'll need to re-authenticate.

    • MFA: Run the aws sts get-session-token command again, providing your MFA serial and a new token.
      bash aws sts get-session-token --serial-number arn:aws:iam::123456789012:mfa/your-user --token-code 123456
      Then, update your ~/.aws/credentials file with the new AccessKeyId, SecretAccessKey, and SessionToken.
    • Assume Role: If you're assuming a role, run the aws sts assume-role command again.
      bash aws sts assume-role --role-arn arn:aws:iam::123456789012:role/YourRole --role-session-name MySession
      Similarly, update your credentials. Many scripts automate this process by directly exporting the environment variables from the assume-role output.
  5. Check System Clock Skew:
    Verify your system's time accuracy.

    • Linux/macOS: date
    • Windows: w32tm /query /status or check the system clock in settings.
      If your clock is significantly off (minutes, not seconds), correct it. Most modern OSes sync automatically, but in VM environments, I've seen this occasionally surface.
  6. Rotate IAM User Access Keys (Last Resort for Static Keys):
    If you're using long-term IAM user access keys, and you've exhausted all other options, the key might be deactivated or compromised.

    • Go to the IAM console -> Users -> [Your User] -> Security credentials.
    • Deactivate the current access key.
    • Create a new access key.
    • IMPORTANT: Update your ~/.aws/credentials file or environment variables with the new access key ID and secret access key immediately. Remember to delete the old key after confirming the new one works.

Code Examples

Here are some quick, copy-paste ready examples for troubleshooting:

1. Checking current AWS identity:

aws sts get-caller-identity

2. Unsetting AWS environment variables (for current shell session):

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_DEFAULT_REGION AWS_REGION AWS_PROFILE

3. Generating new temporary credentials with MFA:
(Replace 123456789012 with your account ID, your-user with your IAM user, and 123456 with your current MFA token.)

AWS_SESSION_OUTPUT=$(aws sts get-session-token \
    --serial-number arn:aws:iam::123456789012:mfa/your-user \
    --token-code 123456 \
    --duration-seconds 3600) # 1 hour duration
export AWS_ACCESS_KEY_ID=$(echo $AWS_SESSION_OUTPUT | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $AWS_SESSION_OUTPUT | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $AWS_SESSION_OUTPUT | jq -r .Credentials.SessionToken)
echo "Temporary credentials updated. Valid for 1 hour."
aws sts get-caller-identity

Note: This example assumes jq is installed for parsing JSON.

4. Assuming an IAM role and setting environment variables:
(Replace 123456789012 with your account ID and YourRole with the role name.)

AWS_ROLE_OUTPUT=$(aws sts assume-role \
    --role-arn arn:aws:iam::123456789012:role/YourRole \
    --role-session-name MyCliSession \
    --duration-seconds 3600) # 1 hour duration
export AWS_ACCESS_KEY_ID=$(echo $AWS_ROLE_OUTPUT | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $AWS_ROLE_OUTPUT | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $AWS_ROLE_OUTPUT | jq -r .Credentials.SessionToken)
echo "Assumed role 'YourRole'. Temporary credentials valid for 1 hour."
aws sts get-caller-identity

5. Python SDK example of credential loading:
If your code is failing, understanding the credential provider chain is key.

import boto3
from botocore.exceptions import ClientError

try:
    # This will use the default credential chain (env vars, config file, EC2 metadata)
    client = boto3.client('s3')
    response = client.list_buckets()
    print("Successfully listed S3 buckets:")
    for bucket in response['Buckets']:
        print(f"- {bucket['Name']}")
except ClientError as e:
    if e.response['Error']['Code'] == 'InvalidClientTokenId':
        print(f"Error: InvalidClientTokenId. Details: {e}")
        print("Please check your AWS credentials (environment variables, ~/.aws/credentials, or IAM role).")
    else:
        print(f"An AWS client error occurred: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

# Explicitly using a profile
try:
    session = boto3.Session(profile_name='dev-profile')
    client = session.client('ec2', region_name='us-west-2')
    response = client.describe_instances()
    print(f"Successfully described EC2 instances using 'dev-profile' in us-west-2.")
except ClientError as e:
    if e.response['Error']['Code'] == 'InvalidClientTokenId':
        print(f"Error for 'dev-profile': InvalidClientTokenId. Details: {e}")
    else:
        print(f"An AWS client error occurred for 'dev-profile': {e}")

Environment-Specific Notes

The source and validity of AWS credentials vary significantly depending on the execution environment.

  • Local Development:
    On your local machine, credentials are most commonly sourced from:

    1. Environment Variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN. These take highest precedence.
    2. Shared Credentials File (~/.aws/credentials): This is where aws configure stores your static or temporary credentials under profiles.
    3. Shared Config File (~/.aws/config): Defines profiles, roles to assume, and default regions.
      When troubleshooting locally, always start by checking environment variables and then your ~/.aws files. I've often seen junior engineers accidentally leave old export commands in their shell configs, causing headaches.
  • Docker Containers:
    Inside a Docker container, credentials need to be explicitly passed in. Common methods include:

    1. Environment Variables: Passed during container creation (-e AWS_ACCESS_KEY_ID=...) or defined in the Dockerfile (less secure for sensitive keys) or docker-compose.yml. This is the most common way.
    2. Volume Mounts: Mounting ~/.aws directory from the host into the container (-v ~/.aws:/root/.aws). This grants the container access to your host's configured profiles.
    3. IAM Roles for ECS/EKS tasks: Best practice for containers running on AWS-managed services.
      If you're getting InvalidClientTokenId in a Docker container, check how credentials are being provided. Often, expired temporary credentials were baked into an image or passed as environment variables without being refreshed.
  • Cloud Environments (EC2, ECS, Lambda, EKS):
    In AWS's native compute services, the preferred and most secure method for providing credentials is via IAM Roles.

    • EC2 Instances: An IAM role attached to an EC2 instance allows applications running on that instance to automatically obtain temporary credentials from the EC2 Instance Metadata Service. There are no static keys stored on the instance itself.
    • Lambda Functions: A Lambda function execution role grants it permissions. The runtime automatically assumes this role.
    • ECS/EKS Tasks: Task execution roles and task roles provide credentials to containers without explicit keys.
      If you see InvalidClientTokenId in these environments, it almost always points to one of two things:
      1. Role Configuration Issue: The IAM role itself might be misconfigured, deleted, or (less common for this specific error) the trust policy doesn't allow the service to assume it.
      2. Assumed Role Expiration (within code): If your application inside an EC2 instance or Lambda function is trying to assume-role again (e.g., to access resources in another account), and it's caching those assumed role credentials, they might expire. The initial credentials from the instance profile are usually long-lived (hours), but subsequent assumed roles can be shorter.

Frequently Asked Questions

Q: Is InvalidClientTokenId a permissions error?
A: No, it is not a permissions (authorization) error. This error means AWS cannot even authenticate you due to invalid or malformed credentials. A permissions error would typically be AccessDenied or a similar message, meaning AWS recognized who you are but determined you don't have the necessary rights.

Q: How long do temporary AWS credentials usually last?
A: It depends on how they are generated. For MFA sessions via get-session-token, the default is 12 hours (max 36 hours). For role assumption via assume-role, the default is 1 hour (max 12 hours). AWS SSO credentials also have a configurable duration.

Q: Can a wrong AWS region cause this error?
A: Yes. While access keys are technically global, the way credentials are used and validated can be sensitive to the region. For temporary credentials, specifically, if the aws_session_token is tied to a specific endpoint or region, or if your client is desperately trying to reach a service in a region where the token isn't recognized, it can lead to this error. Always ensure your region configuration matches your intent.

Q: My aws sts get-caller-identity command also fails with this error. What does that mean?
A: If get-caller-identity fails, it's a strong indicator that your primary, default AWS credentials (whether from environment variables or your default profile) are invalid. This is the first place to start troubleshooting as it confirms a core credential issue before even attempting to interact with other AWS services.

Q: I'm sure my keys are correct, but it's still failing. What else could it be?
A: Double-check for invisible characters or extra spaces in your keys if you copied and pasted them. Also, re-verify your system clock. If all else fails, and you're using static IAM user access keys, rotating them in the IAM console and configuring the new ones is a definitive way to rule out issues with the old keys.

(None)