The AWS CLI uses two files in ~/.aws/:
~/.aws/credentials— access keys, one section per profile.~/.aws/config— region, output format, SSO settings.
If you only have one AWS account this is overkill, but the moment you have a personal account and a work account — or several work accounts — profiles are what let you keep them all addressable from a single shell. Here's the lay of the land in 2026, starting with the legacy access-key flow and ending with IAM Identity Center, which is what you should actually be using.
Multiple profiles, the basics
Each section in ~/.aws/credentials is a profile. Add new ones beneath [default]:
1[default]
2aws_access_key_id = YOUR_DEFAULT_ACCESS_KEY
3aws_secret_access_key = YOUR_DEFAULT_SECRET_KEY
4
5[personal]
6aws_access_key_id = YOUR_PERSONAL_ACCESS_KEY
7aws_secret_access_key = YOUR_PERSONAL_SECRET_KEY
8
9[work]
10aws_access_key_id = YOUR_WORK_ACCESS_KEY
11aws_secret_access_key = YOUR_WORK_SECRET_KEYIn ~/.aws/config, the section names are prefixed profile (except for [default]):
1[default]
2region = us-west-2
3output = json
4
5[profile personal]
6region = us-west-1
7output = text
8
9[profile work]
10region = eu-west-1
11output = jsonThese files are INI, despite the = syntax looking TOML-ish.
Switching profiles
Use --profile:
1aws s3 ls --profile personalOr set AWS_PROFILE (AWS_DEFAULT_PROFILE is the older name and still works, but AWS_PROFILE wins if both are set):
1export AWS_PROFILE=personalIf --profile is omitted and neither env var is set, the CLI uses [default].
Aliases are convenient when you switch between two or three profiles all day. Add to your shell rc file:
1alias awspersonal="AWS_PROFILE=personal aws"
2alias awswork="AWS_PROFILE=work aws"Then awspersonal s3 ls runs against the personal profile without changing the env for the rest of the shell.
IAM Identity Center: the right way in 2026
What used to be called "AWS SSO" was renamed IAM Identity Center in mid-2022. The CLI integration was overhauled at the same time — modern AWS CLI v2 (since 2.9) writes a separate [sso-session] block that profiles reference by name, rather than inlining the SSO settings into every profile.
Run:
1aws configure ssoThe wizard prompts for an SSO session name first, then the start URL, region, account, and role:
1SSO session name (Recommended): my-sso
2SSO start URL [None]: https://your-org.awsapps.com/start
3SSO region [None]: eu-north-1
4SSO registration scopes [sso:account:access]:It opens a browser, you click through the device-grant flow, and the wizard writes something like this to ~/.aws/config:
1[sso-session my-sso]
2sso_start_url = https://your-org.awsapps.com/start
3sso_region = eu-north-1
4sso_registration_scopes = sso:account:access
5
6[profile work]
7sso_session = my-sso
8sso_account_id = 123456789012
9sso_role_name = AdministratorAccess
10region = eu-north-1
11output = jsonAfter that, aws s3 ls --profile work just works. When the SSO session expires (12 hours by default), you'll get a token error — re-authenticate with:
1aws sso login --profile workThe CLI does not silently re-launch the browser flow on expiration; you have to ask.
The big win: no long-lived access keys on disk. Temporary credentials are fetched fresh per role assumption and cached under ~/.aws/sso/cache/ until the session expires.
When you're stuck with long-lived keys
Some CI runners, third-party tools, and bootstrap scripts still want raw AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env vars. If you can't avoid them, get them out of the plaintext credentials file.
Option 1: credential_process. Point ~/.aws/config at a tool that returns credentials as JSON. The de-facto choices in 2026:
aws-vault— stores keys in the OS keychain, vends short-lived session tokens to the CLI on demand.granted— same idea, plus per-tab role switching for the AWS console.- Leapp — GUI alternative if you'd rather not drive it from the terminal.
These plug into the AWS CLI through credential_process, so every SDK that reads the shared config picks them up automatically.
Option 2: hand-rolled keychain export. Lower-level, no extra binaries. Stuff the keys into the OS keychain and export them in your shell:
1# macOS
2security add-generic-password -a AWS -s AWS_ACCESS_KEY_ID -w <ACCESS_KEY>
3security add-generic-password -a AWS -s AWS_SECRET_ACCESS_KEY -w <SECRET_KEY>
4
5export AWS_ACCESS_KEY_ID=$(security find-generic-password -a AWS -s AWS_ACCESS_KEY_ID -w)
6export AWS_SECRET_ACCESS_KEY=$(security find-generic-password -a AWS -s AWS_SECRET_ACCESS_KEY -w)1:: Windows
2cmdkey /add:AWS_ACCESS_KEY_ID /user:AWS /pass:<ACCESS_KEY>
3cmdkey /add:AWS_SECRET_ACCESS_KEY /user:AWS /pass:<SECRET_KEY>1# Linux (libsecret)
2secret-tool store --label='AWS access key' service AWS account AWS_ACCESS_KEY_ID
3secret-tool store --label='AWS secret key' service AWS account AWS_SECRET_ACCESS_KEY
4
5export AWS_ACCESS_KEY_ID=$(secret-tool lookup service AWS account AWS_ACCESS_KEY_ID)
6export AWS_SECRET_ACCESS_KEY=$(secret-tool lookup service AWS account AWS_SECRET_ACCESS_KEY)secret-tool matches secrets by attribute key/value pairs — the service and account attributes have to be identical between the store and lookup calls. The actual secret is read from stdin during store.
Both options beat plaintext in ~/.aws/credentials. Both are still worse than IAM Identity Center.