AWS resolves credentials in a specific order. The first source that has valid credentials wins. This tool shows you exactly which source is winning and why your commands are authenticating the way they are.
Everything runs in your browser. No credentials or commands are sent to any server.
Click each step to see what AWS checks and what can go wrong
What AWS checks
The --profile flag passed directly on the command line
aws s3 ls --profile myprofile Why it wins
Command line flags have the highest precedence. If you pass --profile on the command line it wins regardless of any environment variables or config files.
Gotcha
This is why adding --profile myprofile to a failing command often fixes it — you are bypassing whatever credential source was winning before.
What AWS checks
These three environment variables in the current shell session
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI
export AWS_SESSION_TOKEN=token Why it matters
Environment variables override config files but are overridden by command line flags. They persist for the entire shell session including any scripts or sub-processes you run.
Gotcha
This is the most common cause of using the wrong credentials. A leftover export from a previous assume-role session stays active until you unset all three variables or close the terminal.
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN What AWS checks
Cached SSO tokens stored at ~/.aws/sso/cache/
Why it matters
If you configured SSO with aws configure sso and the session has not expired the cached token is used here.
Gotcha
If your SSO session has expired AWS gives a confusing error rather than prompting you to log in again. The fix is to run aws sso login --profile yourprofile before any other command.
aws sso login --profile yourprofile What AWS checks
The profile named in AWS_PROFILE environment variable or the default profile
# ~/.aws/credentials
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI
[myprofile]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF Gotcha
The most common error is a profile that exists in ~/.aws/credentials but not in ~/.aws/config or vice versa. Run aws configure list-profiles to see what is actually configured.
aws configure list-profiles What AWS checks
A profile in ~/.aws/config that has both role_arn and source_profile set
[profile cross-account]
role_arn = arn:aws:iam::123456789012:role/my-role
source_profile = default
region = us-east-1 Why it matters
This is the correct long-term way to work with assumed roles. AWS CLI automatically calls sts assume-role and refreshes temporary credentials without any manual export.
Gotcha
Most tutorials show the manual export method because it is faster to explain. But the source_profile approach is what AWS recommends because it handles token refresh automatically.
What AWS checks
The metadata service at http://169.254.169.254/latest/meta-data/iam/security-credentials/
Why it matters
Only available when running on EC2, ECS, Lambda, or similar AWS compute. If you reach this step while running locally it means none of the previous sources found credentials.
Gotcha
If your application works on EC2 but fails locally this is why. Your EC2 instance has an IAM role attached. Your local machine does not.
Answer these questions to find which source is winning
Run these in order when you cannot figure out which credentials AWS is using
Check active identity
aws sts get-caller-identity Shows your Account ID, UserId, and ARN. The first command to run when anything is failing with auth errors.
Check credential sources
aws configure list Shows where each configuration value is coming from — env variable, config file, or default. The source column tells you exactly what is winning.
List all profiles
aws configure list-profiles If your profile is not in this list the error will be The config profile could not be found.
Check specific profile
aws sts get-caller-identity --profile myprofile Replace myprofile with your profile name. If this fails the profile credentials are expired or misconfigured.
The most searched AWS credential problems and their fixes
My command works in one terminal but not another
You exported credentials in one terminal session that are not present in the other. Environment variables only exist in the shell where they were set.
Fix
Run env | grep AWS_ in both terminals to compare. Use a named profile in ~/.aws/config instead of environment variables for consistent behavior across sessions.
My application works on EC2 but fails on my laptop
Your EC2 instance has an IAM role attached via instance profile. Your laptop has no such role so credential resolution falls through all 6 steps and finds nothing.
Fix
Configure a local profile with aws configure --profile dev that has credentials matching the permissions your EC2 role has.
I assumed a role but AWS is using my old credentials
After running aws sts assume-role you did not export the returned credentials into environment variables or you are in a different shell session.
Fix
Export all three variables — AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN — from the assume-role output. All three are required. Missing AWS_SESSION_TOKEN causes InvalidClientTokenId.
My credentials worked yesterday but fail today
Temporary credentials from an assumed role or SSO session have expired. Default session duration is 1 hour for assumed roles.
Fix
Run aws sts get-caller-identity to confirm the identity. Then run aws sso login --profile yourprofile for SSO or re-run the assume-role command for role-based credentials.
I get Access Denied but I can see the resource in the console
The IAM identity you are using via CLI is different from the identity you are logged in as in the console. Run aws sts get-caller-identity to confirm.
Fix
Run aws sts get-caller-identity and compare the returned ARN with the identity shown in the top right of the AWS console. They are likely different.
The AWS credential provider chain is the ordered list of places the AWS CLI and SDKs look for credentials before they give up and throw an error. It exists because AWS needs to support a huge range of environments with a single consistent tool. The same aws command needs to work correctly whether you are running it from a laptop with a named profile, a CI pipeline with environment variables injected by a secrets manager, or an EC2 instance with an IAM role attached and no credentials configured anywhere at all. Rather than forcing every environment to configure credentials the same way, AWS checks a fixed sequence of sources and uses the first one that resolves successfully.
This design choice is also why the chain causes so much confusion. Because every source is checked automatically and silently, there is no built in signal telling you which source actually won. Two engineers on the same team, running what looks like the exact same command, can authenticate as two completely different IAM identities because one of them has a leftover AWS_PROFILE variable set in their shell and the other does not. Nothing in the terminal output warns you this is happening. The command either works with the wrong permissions or fails with an error that gives no indication of which of the six sources was actually consulted.
Understanding the order of precedence turns this from a mystery into a checklist. Once you know that command line flags beat environment variables, which beat the SSO cache, which beat named profiles, which beat source_profile role assumption, which beat EC2 instance metadata, you can work through the list from the top down and find the source that is actually active in seconds. This is exactly what aws configure list is built to do. It prints, for every configuration value, which of these sources it came from, and that single command resolves a large share of AWS authentication problems on its own.
Engineers who internalize the credential chain also write more reliable infrastructure. They know to avoid exporting long lived credentials into a shell session that will outlive the task at hand. They design CI pipelines around short lived role assumption instead of static keys baked into environment variables. And when something breaks in production, they know to run aws sts get-caller-identity first, before touching anything else, because confirming which identity is actually active is always the fastest way to rule out half of the possible causes.
AWS credential errors are hard to debug because the error message describes the symptom, not the cause, and the same symptom can come from any of six unrelated sources. An error like Unable to locate credentials or InvalidClientTokenId tells you that authentication failed, but it does not tell you which of the six steps in the chain actually produced that failure. You could be missing credentials entirely, or you could have credentials from the wrong source entirely overriding the ones you meant to use. The message looks identical either way.
The order of precedence makes this worse rather than better, because it means a valid, correctly configured credential source can be silently ignored. A named profile with the exact right permissions sitting in ~/.aws/config is completely irrelevant if an old AWS_ACCESS_KEY_ID environment variable from an unrelated project is still exported in that shell. The CLI is not broken in this scenario. It is doing exactly what it is designed to do, checking environment variables before config files, but the behavior looks like a bug to anyone who does not know the precedence order exists.
A second layer of confusion comes from temporary credentials. SSO sessions and assumed roles both expire, usually after an hour, and AWS does not proactively warn you when that happens. The command that worked five minutes ago starts failing with ExpiredToken or a similarly generic error, with no obvious link back to the fact that a clock somewhere quietly ran out. Engineers who do not know to check session expiry first often spend far longer investigating IAM policies or network issues than the actual problem requires.
The mental model that resolves most of this confusion is to stop asking why this is failing and start asking which of the six sources is currently winning. That reframes debugging from an open ended search into a short, ordered checklist: check command line flags, then environment variables, then the SSO cache, then named profiles, then source_profile role assumption, then instance metadata. Running aws configure list and aws sts get-caller-identity together answers that question directly, which is why those two commands resolve the overwhelming majority of AWS credential issues in practice.