By the end you'll know
- Three ways to sign the AWS CLI in, and why the oldest one, access keys, is the one to avoid
- How
aws loginturns your console sign-in into temporary credentials on your own machine - What a profile is, where its settings live, and which setting wins when several disagree
- How to ask for output as a table, text or JSON, and trim it with
--query - What happens when a session ends, and how to sign out on purpose
- The trap of an old access key that quietly takes priority, and how to spot it
Before you start
- You need: the account from Lesson 2, and a Mac, Linux or Windows machine with a browser.
- Cost: $0. Signing in, and every command in this lesson, only reads.
- The script:
cli-tour.shfrom the practice folder'slesson-04. It only reads, only uses the bakery's profile, and never prints an account ID, a key or any other profile on your machine. - Where you run things: your own machine's terminal, labelled (Your machine). CloudShell's job is done.
- Every output below is from a real run on November 9, 2026, on a Mac. Account numbers, session names and a sign-in address are hidden, and the lesson says where.
The short version
- The AWS CLI (command line interface) is the
awscommand. Everything you can click in the console, it can do, and scripts can run it. - Never sign it in with an access key if you can avoid it. A key lives in a file in your home folder until someone deletes it, and that file is what leaks.
aws loginsigns in through your browser and keeps temporary credentials that refresh every 15 minutes, for up to 12 hours. It needs CLI version 2.32.0 or later.- A profile is a named set of settings in
~/.aws/config. Name it, and you can't mix up accounts. - Command-line options beat environment variables, which beat the files.
aws configure listshows where each setting came from. --outputand--querymake answers readable, for people and for scripts.
What this lesson costs
| Part | Cost |
|---|---|
| Installing the AWS CLI | $0 |
Signing in with aws login | $0 |
| Read-only commands: who am I, Availability Zones | $0 |
| This lesson | $0, and nothing created |
Three ways to sign the CLI in
The CLI needs credentials, like every other way into AWS. There are three common ways to give it some:
| Command | What it stores on your machine | Lasts | Use it when |
|---|---|---|---|
aws configure | An access key and its secret, in ~/.aws/credentials | Until someone deletes the key | Almost never. Only for a tool that can't use anything else. |
aws login | Temporary credentials from your console sign-in, in ~/.aws/login/cache | 15 minutes at a time, refreshed for up to 12 hours | You sign in to the console as a root user, an IAM user, or through federation, like this track's Builder ID account |
aws configure sso, then aws sso login | Temporary credentials from IAM Identity Center | Hours, set by the company | Your company signs you in through Identity Center |
For years, the first tutorial everyone followed was aws configure: paste an access key, done. That key then sits in a plain text file in your home folder, works from anywhere in the world, and never expires. Copy the folder, back it up, push it to GitHub by mistake, and the key goes with it. Lesson 2's leaked-key bills start here.
aws login arrived in November 2025 to end that. It opens your browser, you sign in to the console as you normally would, MFA included, and the CLI gets temporary credentials instead of a key.
Install it, or update it
(Your machine)
aws --version
aws-cli/2.25.14 Python/3.12.9 Darwin/25.6.0 exe/x86_64
Two problems in one line. 2.25.14 is older than 2.32.0, so aws login doesn't exist yet. And exe/x86_64 is the version for Intel processors, running on an Apple silicon Mac through Rosetta, Apple's translator: it works, but more slowly.
Update it the way it was installed, or you end up with two copies and whichever comes first in your PATH, the list of folders your shell searches, wins. Check first:
(Your machine)
which aws
ls -l "$(which aws)"
/usr/local/bin/aws
lrwxr-xr-x 1 root wheel 22 Apr 9 2025 /usr/local/bin/aws -> /usr/local/aws-cli/aws
/usr/local/aws-cli/ is AWS's own Mac installer, so update with that installer:
(Your machine)
cd ~/Downloads
curl -o AWSCLIV2.pkg https://awscli.amazonaws.com/AWSCLIV2.pkg
sudo installer -pkg AWSCLIV2.pkg -target /
aws --version
installer: Package name is AWS Command Line Interface
installer: Installing at base path /
installer: The install was successful.
aws-cli/2.39.7 Python/3.14.8 Darwin/25.6.0 exe/arm64
The download's progress lines and the password prompt are left out. 2.39.7, and exe/arm64, native this time. If which aws had pointed into a Homebrew folder instead, brew upgrade awscli would be the update. On Linux and Windows, AWS's install guide (opens in a new tab) has the matching installer.
Sign in with aws login
(Your machine)
aws login --profile juniper-rye
| Part | What it does |
|---|---|
| aws login | Opens your browser to AWS's sign-in page, then waits for you |
| --profile juniper-rye | Saves this sign-in under its own name, separate from anything else on your machine |
Check which account you're signing in to
Your browser may remember another AWS account. On the first try here, the sign-in page opened as a classic IAM user sign-in, with a different account's ID already filled in. Signing in there would have pointed this profile at the wrong account. For a new-sign-up account, choose Change to new experience and sign in with your Builder ID. Then check, below, who the profile really is.
After the browser sign-in, the terminal finishes on its own:
Attempting to open your default browser. If the browser does not open, open the following URL.
If you are unable to open the URL on this device, run this command again with the '--remote' option.
https://us-east-2.signin.aws.amazon.com/v1/authorize?(the rest of the address removed)
Updated profile juniper-rye to use arn:aws:sts::111122223333:assumed-role/AccountFullAccessRole/(session name removed) credentials.
Use "--profile juniper-rye" to use the new credentials, such as "aws sts get-caller-identity --profile juniper-rye"
The account ID and session name are replaced here, and the sign-in address is cut short. The first time, the CLI also asked "Configure AWS skills and the AWS MCP server for your AI coding agent(s)?" That would give coding agents access to the account. Answer n for now.
Check who the profile is, printing only the identity's kind and name:
(Your machine)
aws sts get-caller-identity --profile juniper-rye --query Arn --output text | cut -d/ -f1-2 | cut -d: -f6
assumed-role/AccountFullAccessRole
| Part | What it does |
|---|---|
| aws sts get-caller-identity | Asks AWS "who am I?" It works for any identity, with no permissions needed |
| --query Arn --output text | Keeps only the identity's ARN, as plain text |
| cut -d/ -f1-2 \| cut -d: -f6 | Trims the ARN to the kind and name, leaving out the account ID and session name |
The same role the console uses, which is right for a Builder ID account. No access key was created or stored.
Profiles, and which setting wins
A profile is a named set of settings in ~/.aws/config. aws login wrote this one; it looks roughly like this, with the account and session hidden:
[profile juniper-rye]
login_session = arn:aws:sts::111122223333:assumed-role/AccountFullAccessRole/...
region = us-east-2
Use a profile with --profile juniper-rye on each command, or for a whole terminal session:
(Your machine)
export AWS_PROFILE=juniper-rye
When the same setting comes from several places, the AWS CLI picks in this order, first one wins:
- Command-line options, like
--profile,--regionand--output - Environment variables, like
AWS_PROFILE,AWS_REGIONandAWS_ACCESS_KEY_ID - Credentials from roles and sign-ins, such as Identity Center
- The credentials file,
~/.aws/credentials, whereaws configurekeeps access keys - The config file,
~/.aws/config
That order is why an old key can quietly win. A forgotten AWS_ACCESS_KEY_ID in your shell, or an old key under the same profile in the credentials file, gets used before your fresh sign-in, and commands land in the wrong account or fail with ExpiredToken. The tour below checks for exactly that.
A tour, and a real failure on the way
cli-tour.sh asks a few read-only questions with the juniper-rye profile:
(Your machine)
cd ~/Apps/aws-practice/lesson-04
chmod +x cli-tour.sh
./cli-tour.sh
The first run:
== The CLI
aws-cli/2.39.7
== Who this profile is
assumed-role/AccountFullAccessRole
== Where its settings come from
NAME : VALUE : TYPE : LOCATION
profile : juniper-rye : manual : --profile
region : <not set> : None : None
credential type: login session (aws login), refreshed automatically
stored access keys for this profile: none
== The same question, three output formats
-- --output table
aws: [ERROR]: An error occurred (NoRegion): You must specify a region. You can also configure your region by running "aws configure".
The other three Availability Zone questions failed with the same error, and the last section came out the same as in the run below.
The sign-in worked, and there's no stored key to worry about, but every Availability Zone question failed. aws configure list says why: region : <not set>. Most AWS services work per Region, so the CLI has to know which one. "Who am I?" worked without one because AWS STS answers globally.
The fix is to store the Region in the profile:
(Your machine)
aws configure set region us-east-2 --profile juniper-rye
| Part | What it does |
|---|---|
| aws configure set region us-east-2 | Writes one setting to the config file |
| --profile juniper-rye | Into this profile's section only; other profiles aren't touched |
Use your own project's Region; Lesson 2's CloudShell check showed it. Run the tour again:
(Your machine)
./cli-tour.sh
== The CLI
aws-cli/2.39.7
== Who this profile is
assumed-role/AccountFullAccessRole
== Where its settings come from
NAME : VALUE : TYPE : LOCATION
profile : juniper-rye : manual : --profile
region : us-east-2 : config-file : ~/.aws/config
credential type: login session (aws login), refreshed automatically
stored access keys for this profile: none
== The same question, three output formats
-- --output table
-----------------------------------------
| DescribeAvailabilityZones |
+------------+------------+-------------+
| us-east-2a| use2-az1 | available |
| us-east-2b| use2-az2 | available |
| us-east-2c| use2-az3 | available |
+------------+------------+-------------+
-- --output text
us-east-2a use2-az1 available
us-east-2b use2-az2 available
us-east-2c use2-az3 available
-- --output json (first zone only)
{
"name": "us-east-2a",
"id": "use2-az1",
"state": "available"
}
== Filtering with --query: just the names, one per line
us-east-2a
us-east-2b
us-east-2c
== Another Region than the project's
us-west-2: denied, explicit deny in a service control policy
eu-west-1: denied, explicit deny in a service control policy
What each part shows:
- Where each setting came from. The LOCATION column is the first thing to check when a command uses the wrong account or Region:
--profilefrom the command line, the Region from~/.aws/config. - Three output formats for one question.
tableis for people,textis for shell scripts (tab-separated, one row per line), andjson, the default, keeps the full structure for programs. --queryfilters the answer before it's printed, using a small language called JMESPath.AvailabilityZones[].ZoneNamemeans "the ZoneName of every zone".- Zone names and zone IDs.
us-east-2ais a name;use2-az1is an AZ ID, the same physical place in every account. In a few older Regions, the same name could point to different physical zones in different accounts; AWS says accounts created from November 2025 get the same mapping everywhere. When you compare zones across accounts, use the ID. - Other Regions are fenced off. In the new sign-up, the service control policy stops you even looking at other Regions.
Signing out, and what happens after
A session ends on its own after the role's session length, at most 12 hours. To end it now:
(Your machine)
aws logout --profile juniper-rye
Removed cached login credentials for profile 'juniper-rye'. Note, any local developer tools that have already loaded the access token may continue to use it until its expiration. Access tokens expire in 15 minutes.
Read the second sentence: a tool that already loaded the credentials keeps them for up to 15 minutes. Short-lived credentials limit how long a copied one stays useful; they don't stop it the instant you sign out.
Then try to use the profile:
(Your machine)
aws sts get-caller-identity --profile juniper-rye --query Arn --output text 2>&1 | sed -E 's/[0-9]{12}/111122223333/g'
aws: [ERROR]: Error loading login session token: Unable to load a existing login session for session arn:aws:sts::111122223333:assumed-role/AccountFullAccessRole/(session name removed), Please reauthenticate with 'aws login'.
The sed replaces the account ID; the session name was removed by hand. The error tells you exactly what to do. Sign in again before the next lesson:
(Your machine)
aws login --profile juniper-rye
On a machine without a browser, like a server you've connected to, aws login --remote prints an address to open on another device and asks you to paste back a code.
In real systems
- People use Identity Center profiles, one per account and role, set up with
aws configure sso. Signing in once covers every account they're allowed into. - Programs never sign in like people. A server gets its role's credentials automatically, a Lambda function from its execution role, a pipeline through OIDC (OpenID Connect), Lesson 31. None of them store keys.
- Long-lived keys get hunted down. Security teams look for them, check when each was last used, and remove them. Where one is truly needed, it's rotated and watched.
- Profiles are named after accounts and roles, like
bakery-prod-readonly, so a command's target is obvious from the command itself.
Spot the problem
Work out what's wrong before you read the explanation.
"I signed in, but I'm in the wrong account." A developer runs aws login --profile bakery, signs in fine, and aws sts get-caller-identity --profile bakery works. But every command lands in an old test account they stopped using a year ago, and some fail with ExpiredToken. What's going on? An old access key under the same profile name in ~/.aws/credentials, or an AWS_ACCESS_KEY_ID left set in their shell, is taking priority over the login session. The credentials file and environment variables come before it in the order above. The fix: run aws configure list --profile bakery and read the TYPE and LOCATION columns, then delete the old key from the credentials file, or unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN. Then check: does aws configure list show the credentials coming from the login session, and does cli-tour.sh say "stored access keys for this profile: none"?
Keep this
| Command | Does |
|---|---|
aws --version | Shows the version; aws login needs 2.32.0 or later |
aws login --profile NAME | Signs in through the browser; temporary credentials, no keys |
aws sts get-caller-identity | Who am I, right now? |
aws configure list --profile NAME | Which settings are used, and where each came from |
aws configure set region REGION --profile NAME | Stores one setting in a profile |
export AWS_PROFILE=NAME | Uses a profile for the rest of this terminal session |
--output table, text, json | For people, for shell scripts, for programs |
--query 'List[].Field' | Keeps only what you ask for |
aws logout --profile NAME | Removes the cached credentials; copies already loaded last up to 15 minutes |
Where you are now
Your own machine can work with the account, signed in through your browser and MFA, with credentials that refresh themselves and expire on their own, and no access key anywhere. You know where a profile's settings live, which setting wins when several disagree, how to make the CLI's answers readable, and how to spot an old key taking priority. From here on, most hands-on work runs on your machine. Next, Lesson 5 is about Regions and shared responsibility: where your resources live, and which security jobs are AWS's and which are yours.
Check yourself
What does aws login store on your machine?
--profile on the command line says one account, and AWS_PROFILE says another. Which wins?
Commands fail with NoRegion, but get-caller-identity works. Why?
Which output format suits a shell script best?
You compare a zone in your account with a colleague's account. What should you compare?
After aws logout, how long can a tool that already loaded the credentials keep using them?
A login works, but commands land in an old account. What's the likely cause?
Key terms
- AWS CLI (command line interface): the
awscommand, for anything you can do in the console. - Access key: a long-lived credential for programs, stored in
~/.aws/credentialsbyaws configure. Avoid it. aws login: signs the CLI in with your console sign-in and caches temporary credentials. Needs version 2.32.0 or later.aws configure sso: sets up sign-in through IAM Identity Center, for company accounts.- Profile: a named set of settings in
~/.aws/config, chosen with--profileorAWS_PROFILE. - Precedence: the order the CLI picks settings in: command-line options, environment variables, then the files.
--output: table, text or json.--query: a JMESPath expression that keeps only part of the answer.- AZ ID: an Availability Zone's ID, like
use2-az1, the same physical place in every account. - PATH: the list of folders your shell searches for commands; the first match wins.
Go deeper
- AWS: Login for AWS local development using console credentials (opens in a new tab), everything
aws loginandaws logoutcan do. - AWS: Configuration and credentials precedence (opens in a new tab), the full order.
- AWS: AZ IDs (opens in a new tab), names versus IDs, and the November 2025 change.
- AWS Builder Center: what aws login can and can't do (opens in a new tab), including its limits for automation.
- Try: run
aws ec2 describe-availability-zones --profile juniper-rye --query 'AvailabilityZones[].{zone:ZoneName,id:ZoneId}' --output table. What changes compared with the tour's table, and why?