15.7
Step Functions and Cognito
Orchestrated workflows, user pools vs identity pools, and row-level security for app users.
24 min Reading + animations
Tip: tap or hover any dotted-underlined term to see what it means.
By the end of this lesson you will be able to
- Explain why a multi-step process (an order, a loan, a data job) belongs in an AWS Step Functions state machine instead of Lambda functions calling each other.
- Read and write a small Amazon States Language definition with Task, Choice, Wait, Parallel, Map, Pass, Succeed and Fail states, plus Retry and Catch rules.
- Pause a workflow for a human with the callback pattern (
.waitForTaskToken) and know the three service integration patterns. - Choose between Standard and Express workflows from duration, execution guarantee, history and price, and calculate the monthly bill of each.
- Describe a Cognito user pool (sign-up, sign-in, MFA, federation, managed login, JWTs, feature plans) and plug it into API Gateway and an ALB.
- Use a Cognito identity pool to give app users temporary AWS credentials, with guest access and row-level security in DynamoDB (
dynamodb:LeadingKeys). - Tell a user pool from an identity pool, and Cognito from IAM, from the exam keywords.
#Why orchestrate: the trouble with functions calling functions
Lessons 15.1 to 15.6 gave you the parts: Lambda functions, DynamoDB tables, an API in front. Real business processes are rarely one function. They are a sequence of steps with decisions, waits and failures.
You could make the Payment function call the Inventory function directly, and Inventory call Shipping. It works on day one and hurts every day after:
- Every function must know the next one. Change the order of steps and you redeploy three functions.
- Error handling lives in your code. Each function needs its own retry loop, backoff and “undo what I did” logic.
- You pay for waiting. A function that synchronously waits for another is billed for the whole wait, and it can never wait longer than Lambda’s 15-minute limit (lesson 15.2). Waiting two days for a manager is impossible.
- Nobody can see where an order is. The state is scattered across logs of several functions.
Step Functions moves all of that into one place: a state machine that calls each step, passes the data along, retries, catches errors, waits, and records the history of every execution (one run of the workflow, for example one order).
#AWS Step Functions: state machines
#Amazon States Language and Workflow Studio
A state machine is written in the Amazon States Language (ASL), a JSON document that lists the states and how they connect. You rarely type it by hand: Workflow Studio, the drag-and-drop designer in the console (also available in Visual Studio Code through the AWS Toolkit), draws the graph and writes the ASL for you. In the console you then watch every execution as the same graph, each state green, red or in progress, with its input and output.
The order workflow, shortened:
{
"Comment": "Order workflow for the Dhaka shop",
"StartAt": "Charge payment",
"States": {
"Charge payment": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Arguments": { "FunctionName": "payment-example", "Payload": "{% $states.input %}" },
"Output": "{% $states.result.Payload %}",
"Next": "Paid?"
},
"Paid?": {
"Type": "Choice",
"Choices": [{ "Condition": "{% $states.input.payment = 'paid' %}", "Next": "Reserve stock" }],
"Default": "Payment declined"
},
"Reserve stock": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Arguments": { "FunctionName": "inventory-example", "Payload": "{% $states.input %}" },
"Retry": [{
"ErrorEquals": ["Lambda.TooManyRequestsException", "States.TaskFailed"],
"IntervalSeconds": 2, "BackoffRate": 2, "MaxAttempts": 3
}],
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "Refund payment" }],
"Next": "Ship and notify"
},
"Ship and notify": { "Type": "Parallel", "Branches": ["…ship…", "…SNS publish…"], "Next": "Done" },
"Refund payment": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Arguments": { "FunctionName": "refund-example" }, "Next": "Order failed" },
"Payment declined": { "Type": "Fail", "Error": "PaymentDeclined", "Cause": "Card declined" },
"Order failed": { "Type": "Fail", "Error": "OrderFailed" },
"Done": { "Type": "Succeed" }
},
"QueryLanguage": "JSONata"
}
#The eight state types
| State | What it does | Everyday example |
|---|---|---|
| Task | Does one unit of work: invokes a Lambda function, calls an AWS service, runs an ECS task, calls an HTTPS API, or waits for an activity worker | Charge the card |
| Choice | Branches on the data, like an if / switch; always give it a Default | Paid? Declined? |
| Wait | Pauses for a number of seconds or until a timestamp, at no compute cost | Send the review request 7 days after delivery |
| Parallel | Runs several branches at the same time and continues when all finish; one failing branch fails the state | Ship and notify at once |
| Map | Runs the same steps for each item of an array (inline) or of a big data set in S3 (distributed) | Reserve each item of the order |
| Pass | Passes its input to its output, optionally adding or reshaping data; useful for defaults and testing | Add "currency": "BDT" |
| Succeed | Ends the execution (or a branch) successfully | Order complete |
| Fail | Ends the execution as failed, with an error name and cause you choose | Payment declined |
The slide’s feature list in one line: sequence, parallel, conditions (Choice), timeouts, error handling, all as configuration.
One order, one state machine: Step Functions runs the steps
A Dhaka e-commerce shop processes each order in three steps: charge the payment, reserve the stock, ship. Each step is a small Lambda function. Step Functions decides what runs next, retries what fails and remembers where every order is.
Scenario
Start → Task (payment) → Choice → Task (stock) → Parallel (ship + notify) → Succeed.
Execution order-5501
state
Start
orderId
5501
amount
2,450 taka
status
running
The checkout API starts one execution of the state machine per order and hands it the order as JSON input. From here the API is free: it does not wait, and it does not need to know the steps.
#Retry and Catch
Any Task, Parallel or Map state can carry two error-handling blocks.
- Retry: a list of rules, each with
ErrorEquals(which errors),IntervalSeconds(first wait, default 1),BackoffRate(multiplier, default 2.0),MaxAttempts(default 3; 0 means never retry), and optionallyMaxDelaySecondsandJitterStrategy: FULLto spread retries out. With interval 2 and backoff 2, the waits are 2, 4 and 8 seconds. - Catch: once retries are exhausted (or for errors with no retry rule), a matching catcher sends the execution to a recovery state, with the error placed in the data. Without a matching catcher the whole execution fails.
Error names you should recognise: States.ALL (matches every error), States.TaskFailed, States.Timeout (a state ran longer than its TimeoutSeconds, or the execution reached its maximum), States.HeartbeatTimeout, States.Permissions, States.NoChoiceMatched, and service errors such as Lambda.TooManyRequestsException or Lambda.ServiceException, plus any custom error your function throws.
The order animation’s “Catch and refund” scenario is the saga pattern: when a later step fails, run compensating actions that undo the earlier ones (refund the payment, release the stock). Step Functions is the usual way to build sagas on AWS, because the Catch rules make the undo path visible and reliable.
A failed Standard execution can be redriven within 14 days: after you fix the cause, it restarts from the state that failed instead of from the beginning, so the customer is not charged again.
#Waiting for a human: the callback pattern
The slide mentions a human approval feature, and the notes give the exam trick: if a process can take hours or days, for example waiting for manual approval, the answer is Step Functions with a Standard workflow.
Every Task that calls a service uses one of three service integration patterns:
| Pattern | ARN suffix | Step Functions… | Example |
|---|---|---|---|
| Request Response | (none) | Calls the service, gets the HTTP response, moves on immediately | Publish to SNS, put an item in DynamoDB |
| Run a job | .sync | Starts the job and waits until it finishes | Run an ECS task, a Glue job, a Batch job, a child workflow, and continue when it ends |
| Wait for callback | .waitForTaskToken | Sends a task token to someone and pauses until that token comes back | Email a manager, wait for an external system or a person |
With the callback pattern, Step Functions puts a unique task token in the message it sends (an SNS email, an SQS message, a Lambda payload). Whoever finishes the work calls SendTaskSuccess (with the output) or SendTaskFailure (with an error) and passes the token back. Long-running workers can also call SendTaskHeartbeat; if they stop, HeartbeatSeconds fails the task. Always set TimeoutSeconds on a callback Task, or it may wait for the one-year maximum.
Waiting for a human: the task token callback
A microfinance lender approves small loans automatically, but a loan officer must approve any loan where the credit score is borderline. The workflow pauses for days without running anything, then continues the moment the officer clicks.
Scenario
A shop owner in Narayanganj applies for a loan of 5 lakh taka. The app starts a Standard workflow execution with the application as input.
#What Step Functions can call
The slide says Step Functions integrates with EC2, ECS, on-premises servers, API Gateway, SQS and more. Today there are three layers:
- Optimized integrations with special support (
.sync, callbacks, simpler parameters): Lambda, ECS and Fargate, AWS Batch, DynamoDB, SNS, SQS, Glue, SageMaker, EventBridge, API Gateway, Athena, EMR, Bedrock, and other Step Functions workflows (nested workflows). - AWS SDK integrations: call almost any API of over 220 AWS services directly from a Task (
arn:aws:states:::aws-sdk:s3:copyObject), with no Lambda function in between. Older material says “200+ services”; both mean “nearly everything”. - HTTP Task: call any public HTTPS API (a payment gateway, Salesforce) with credentials kept in an EventBridge connection.
For code that runs outside AWS’s managed services, such as a program on an EC2 instance or an on-premises server, use an activity: the worker polls GetActivityTask, does the job and returns the result with the task token. Activities are Standard-only.
Executions start from the console, the SDK or CLI (StartExecution), API Gateway, an EventBridge rule or schedule (lesson 19.5), a Lambda function, or another state machine. Slide use cases: order fulfilment, data processing, web applications, any workflow.
Calling services directly instead of through “glue” Lambda functions is cheaper and has fewer moving parts: a dynamodb:putItem Task has no cold start, no code to patch and no Lambda bill.
#Standard vs Express workflows
When you create a state machine you choose its type, and you cannot change it later. The notes give the headline: Standard runs for up to 1 year (long-running processes), Express for up to 5 minutes (high-volume, fast work). The rest matters just as much:
| Standard | Express | |
|---|---|---|
| Maximum duration | 1 year | 5 minutes |
| Execution guarantee | Exactly-once: each state runs once unless you add Retry | Asynchronous: at-least-once; synchronous: at-most-once |
| Suits | Long, durable, auditable, non-idempotent steps (payments, starting an EMR cluster) | Short, high-volume, idempotent event processing (IoT ingestion, streaming transforms, mobile and API back ends) |
| Price | Per state transition: 0.025 USD per 1,000 (4,000 free a month, forever) | Per execution + duration × memory: 1.00 USD per million, plus 0.06 USD per GB-hour for the first 1,000 GB-hours (lower tiers above) |
| Execution history | Kept by Step Functions for 90 days, visual debugging in the console | Not kept: turn on CloudWatch Logs |
Callback (.waitForTaskToken) and .sync | Yes | No |
| Distributed Map, activities, redrive | Yes | No |
| Start rate (default) | About 300 per second in the largest Regions (token bucket, raisable) | About 6,000 per second; no limit on state transitions |
| How it is started | Asynchronously (StartExecution) | Asynchronous (StartExecution) or synchronous (StartSyncExecution, returns the result, for example behind API Gateway) |
Prices are US East (N. Virginia) list prices, checked October 2026. The Lambda functions and other services a workflow calls are billed separately.
A worked example: an API back end runs 1,000,000 executions a month, each with 10 state transitions, lasting 2 seconds at 64 MB.
- Standard: 10,000,000 transitions − 4,000 free = 9,996,000 × 0.000025 = about 249.90 USD.
- Express: 1,000,000 × 1.00 / 1,000,000 = 1.00 USD for requests; duration 1,000,000 × 2 s × 0.0625 GB = 125,000 GB-seconds = 34.7 GB-hours × 0.06 = 2.08 USD; total about 3.08 USD.
The same workflow is 80 times cheaper on Express, if it is short and idempotent. Flip it around: a loan approval that runs 3,000 times a month with 12 transitions each is 36,000 transitions, 0.80 USD on Standard, and Express cannot do it at all (it waits for days and needs a callback).
Standard or Express: what does one workflow cost?
Pick how often the workflow runs, how many states each run passes through, how long a run takes and how much memory it uses. Say whether it waits for a person or a long job, and whether a step must never run twice. Then calculate a month both ways.
Executions a month
State transitions per execution
Average duration
Memory (billed in 64 MB steps)
Waits for a person or a long job?
A step must never run twice (payments)?
Press “Calculate” to see the result.
#Map at scale: Distributed Map
The inline Map runs iterations inside one execution (up to 40 at a time, and every iteration’s events count toward that execution’s 25,000-entry history), so the whole array must fit in the 256 KiB limit for a state’s input and output. The Distributed Map (Standard only) reads items straight from S3 (a CSV, a JSON array, or every object under a prefix) and starts up to 10,000 child workflow executions in parallel, each of which can be Express. It is the answer for “process millions of S3 objects” with retries and a report of failures, without writing your own fan-out.
#Amazon Cognito: identity for your app’s users
IAM (chapter 2) is for the people and workloads that manage AWS. Your shop’s customers, your app’s riders, your university’s students are not AWS users, and there may be millions of them. Amazon Cognito gives users of your web and mobile apps an identity: sign-up, sign-in, and access control. The notes stress it has two parts, and this is where the exam’s most confusing questions come from:
| User pool (CUP) | Identity pool (CIP, “federated identities”) | |
|---|---|---|
| Notes’ picture | Identity card: proves who you are | Office access card: opens specific doors |
| Job | Authentication (“who are you?”): a user directory with sign-up, sign-in, password reset, MFA | Authorization to AWS (“what may you do in AWS?”): temporary AWS credentials |
| Gives the app | JWTs (ID, access and refresh tokens) | An access key, secret key and session token from STS |
| Used with | Your API (API Gateway, ALB), your backend | AWS services directly: S3, DynamoDB, IoT, Kinesis… |
| Guests | No (only signed-in users) | Yes, optional unauthenticated role |
The two are often used together: the user signs in to the user pool, and the identity pool trusts the user pool’s token and turns it into AWS credentials.
#Cognito user pools
A user pool is a serverless user directory for your web and mobile apps. Features from the slides, verified against today’s service:
- Sign-up and sign-in with a username or email (or phone) and a password, with a password policy you set.
- Email and phone number verification with a code, and password reset (“forgot password”) through the verified address.
- MFA: authenticator app (TOTP), SMS, and email one-time codes; optional or required. Passwordless sign-in with passkeys or one-time codes is also available.
- Federation: let users sign in with Google, Facebook, Apple, Login with Amazon, or a corporate SAML 2.0 or OIDC identity provider, and still get the same tokens from your pool.
- Managed login: Cognito hosts ready-made sign-in, sign-up and reset pages for your domain (the older version is called the hosted UI). It is also an OAuth 2.0 / OIDC authorization server.
- Lambda triggers to customise each stage: pre sign-up (block disposable emails), post confirmation (create a profile row, send a welcome message), pre token generation (add claims), custom auth challenges, user migration from an old database.
- Groups, with optional IAM roles for the identity pool, and user import from CSV.
- Compromised-credential checks and adaptive authentication (the threat protection of the Plus plan): block or challenge sign-ins that use a leaked password or come from an unusual device or place.
After sign-in the pool returns three tokens:
| Token | Format | Says | Default lifetime |
|---|---|---|---|
| ID token | JWT | Who the user is: sub, email, name, groups | 1 hour (5 minutes to 1 day) |
| Access token | JWT | What the app may call: scopes, groups | 1 hour (5 minutes to 1 day) |
| Refresh token | Opaque | Gets new ID and access tokens without a password | 30 days (1 hour to 10 years) |
The JWTs are signed with the pool’s private key. Anyone can verify them with the pool’s public keys (the JWKS URL), without calling Cognito, which is why API Gateway and the ALB can check them at line speed.
#Two front doors: API Gateway and the ALB
The slides show user pools integrating with exactly two AWS front doors:
- API Gateway: the app signs in, gets a token and sends it in the
Authorizationheader. A Cognito user pool authorizer (REST API) or a JWT authorizer (HTTP API) checks signature, expiry, issuer and audience, and passes the claims to the backend; invalid tokens get 401 without touching your code (lesson 15.6). - Application Load Balancer: an HTTPS listener rule with an
authenticate-cognitoaction redirects a browser without a session to the managed login page, exchanges the code for tokens itself, sets a session cookie and forwards the request withx-amzn-oidc-*headers that carry the user’s identity (lesson 6.3). The application behind it needs no login code at all.
Cognito user pool: sign-up, sign-in and tokens
A ride-sharing app keeps its riders in a Cognito user pool. The pool stores the users and their passwords, checks them at sign-in and hands out JWT tokens that API Gateway or an ALB can check without asking Cognito again.
Scenario
Rafi installs the app and signs up with his email and a password. The app calls the user pool directly; there is no user table or password hashing in your own code.
A quick sum: a ride-sharing app with 60,000 monthly active riders on Essentials pays (60,000 − 10,000) × 0.015 = 750 USD a month; on Plus 60,000 × 0.020 = 1,200 USD, the price of automatic breach and risk checks.
#Cognito identity pools
An identity pool gets identities for users so they can obtain temporary AWS credentials and call AWS services directly (or through API Gateway with IAM authorization). It does not store users or passwords; it trusts other identity providers:
- a Cognito user pool,
- social logins (Google, Facebook, Apple, Login with Amazon),
- any SAML or OIDC provider,
- developer-authenticated identities (your own existing login system),
- and, if you allow it, no provider at all: guest (unauthenticated) users.
How it works (the slide’s diagram): the app logs in and gets a token from the provider → exchanges the token at the identity pool → the pool validates the token, gives the user a stable identity ID, picks an IAM role and calls STS (AssumeRoleWithWebIdentity, the federation call from lesson 2.4) → the app receives temporary credentials (about one hour; the SDK renews them) → direct access to the private S3 bucket and the DynamoDB table.
Which role? By default, one role for authenticated users and one for guests. You can also map users to roles by rules (for example, a claim department = finance) or take the role from the user pool group in the token. Each role’s trust policy names cognito-identity.amazonaws.com and the identity pool ID, so nobody else can assume it.
#Row-level security with policy variables
One role serves every user, but each user must reach only their own data. The trick is the policy variable ${cognito-identity.amazonaws.com:sub}, which IAM replaces with the caller’s identity ID at request time (the same idea as ${aws:username} in lesson 2.1).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "OwnPhotosOnly",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::student-photos-example/${cognito-identity.amazonaws.com:sub}/*"
},
{
"Sid": "OwnGradesOnly",
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:Query", "dynamodb:PutItem", "dynamodb:UpdateItem"],
"Resource": "arn:aws:dynamodb:ap-southeast-1:111122223333:table/grades-example",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
}
}
}
]
}
dynamodb:LeadingKeys is the partition key value of the items a request touches (lesson 15.4). The condition says “only items whose partition key is your own identity ID”. That is row-level security in DynamoDB (the slide title) with zero authorization code. Two details people get wrong: the table’s partition key must hold the identity pool’s identity ID (like ap-southeast-1:7c1e…), not the user pool’s sub; and a Scan cannot be limited this way, so leave it out of the policy.
Cognito identity pool: AWS credentials for app users
A university app lets each student upload a profile photo to S3 and read their own grades from DynamoDB, directly from the phone, with no API in between. The identity pool turns a login into temporary AWS credentials that only reach the student’s own data.
Scenario
User pool login → token exchanged at the identity pool → STS credentials → direct PUT to the student’s own S3 folder.
What the app holds
ID token
from the user pool
AWS credentials
none yet
Nusrat signs in to the university’s user pool and gets an ID token. That token proves who she is, but S3 does not accept it: every S3 request must be signed with AWS credentials.
#User pool or identity pool: the exam keywords
The notes’ cheat sheet:
- “Sign-up”, “sign-in”, “JWT tokens”, “user directory”, “social login for my app”, “hosted login page”, “authenticate users of API Gateway / ALB” → Cognito user pool.
- “Temporary AWS credentials”, “give access to S3 / DynamoDB directly from a mobile app”, “unauthenticated / guest access”, “per-user folder in S3”, “fine-grained access to DynamoDB items” → Cognito identity pool.
- Both, when the app signs users in and calls AWS directly.
Memory aid from the notes: User pool = authentication (who are you?); identity pool = authorization (what may you do in AWS?).
#Cognito or IAM?
The slide’s keywords for picking Cognito over IAM: “hundreds of users” (or thousands, millions), “mobile users”, “authenticate with SAML” for an application. IAM users are for a limited number of people who administer AWS; for a workforce signing in to AWS accounts, the modern answer is IAM Identity Center (lesson 20.3). Creating an IAM user per app customer, or embedding an IAM user’s access keys in a mobile app, is always wrong: the keys are long-term, and anyone who unpacks the app gets them.
#What goes wrong
| Symptom | Cause | Fix |
|---|---|---|
Execution fails with States.NoChoiceMatched | A Choice state with no matching rule and no Default | Always add Default |
| Customer charged, no product, execution “failed” | A later step failed and there was no Catch | Add Catch with compensating steps (saga), then redrive |
| Payment taken twice | Retry on a non-idempotent step, or async Express (at-least-once) | Idempotency key; Standard for non-idempotent steps |
| Execution waits forever | Callback Task without TimeoutSeconds; the token was lost | Set a timeout and a Catch on States.Timeout; heartbeats for long workers |
| Creating the state machine fails | .waitForTaskToken, .sync or Distributed Map in an Express workflow | Use Standard (or a Standard parent) |
| Express run killed at 5 minutes | Work longer than the Express limit | Standard, or split the work |
| “Execution history exceeded” failure | A Standard execution reached 25,000 history events (a long loop) | Move the loop to a child workflow or Distributed Map |
States.DataLimitExceeded | State input or output over 256 KiB | Store the data in S3 and pass the key |
| Express failures invisible | Express keeps no history | Enable CloudWatch Logs (and X-Ray) |
Task fails with States.Permissions / AccessDenied | The state machine’s execution role lacks the permission | Add the action to the role (e.g. lambda:InvokeFunction) |
| API returns 401 every morning | Access token expired after 1 hour | Use the refresh token; SDKs do this automatically |
| S3 returns 403 for a signed-in user | App sent the user pool JWT to S3 | Identity pool, or your API / presigned URL |
| DynamoDB AccessDenied for the right user | Table keyed by user pool sub, policy uses the identity ID | Key items by the identity pool identity ID |
| Guests can write data | Unauthenticated role too broad | Give the guest role read-only, public data |
| Breached passwords not blocked | Lite or Essentials plan | Plus plan threat protection, or enforce MFA |
#Step Functions and Cognito in system design
- Order and payment pipelines: Standard workflow, Catch with compensations (saga), idempotency keys, SNS notifications, redrive after fixes.
- Human-in-the-loop: loan approval, content moderation, customer identity checks:
.waitForTaskTokenwith a timeout and an escalation path. - Data processing: Distributed Map over S3, a Glue or EMR job with
.sync, Athena queries as SDK integration Tasks; Express children for per-record work. - High-volume event processing: Kinesis or SQS → Lambda → asynchronous Express workflow, or API Gateway → synchronous Express workflow for an API that calls several services.
- App identity: user pool + API Gateway authorizer for the API; identity pool for direct S3 uploads and DynamoDB reads; WAF on the user pool and API (chapter 21); the full mobile-app architecture, with DAX and caching, comes in lesson 15.8.
Step Functions vs SQS: SQS buffers and decouples (a producer does not care who processes the message or when); Step Functions coordinates a known sequence and tracks state. They combine well: a Task can send to SQS with a task token and wait for the consumer’s answer.
Which one fits?
Pick a scenario, read its keywords, and choose: a Standard or Express workflow, a Cognito user pool or identity pool, or plain IAM. Then read why.
1. Choose a scenario(Right first time: 0/10)
A microfinance lender scores each loan application automatically, but borderline cases must wait for a loan officer to approve them, which can take up to three days.
Keywords:manual approvaldayscallback
2. Your answer
#Try it yourself
Region ap-southeast-1, account 111122223333; output trimmed. The functions and roles must already exist.
# 1. Create the order state machine (Standard) from the ASL file above
aws stepfunctions create-state-machine --name order-example --type STANDARD \
--definition file://order.asl.json \
--role-arn arn:aws:iam::111122223333:role/sfn-order-example
# { "stateMachineArn": "arn:aws:states:ap-southeast-1:111122223333:stateMachine:order-example",
# "creationDate": "2026-10-28T10:02:11.402000+06:00" }
# 2. Start one execution per order; the name makes the start idempotent
aws stepfunctions start-execution \
--state-machine-arn arn:aws:states:ap-southeast-1:111122223333:stateMachine:order-example \
--name order-5501 --input '{"orderId":"5501","amount":2450,"items":["T-shirt","Panjabi"]}'
# { "executionArn": "arn:aws:states:ap-southeast-1:111122223333:execution:order-example:order-5501",
# "startDate": "2026-10-28T10:03:40.118000+06:00" }
aws stepfunctions describe-execution \
--execution-arn arn:aws:states:ap-southeast-1:111122223333:execution:order-example:order-5501 \
--query '{status:status,output:output}'
# { "status": "SUCCEEDED", "output": "{\"orderId\":\"5501\",\"payment\":\"paid\",\"reservation\":\"R-77\"}" }
aws stepfunctions get-execution-history \
--execution-arn arn:aws:states:ap-southeast-1:111122223333:execution:order-example:order-5501 \
--query 'events[].type' --output text
# ExecutionStarted TaskStateEntered TaskScheduled TaskStarted TaskSucceeded TaskStateExited
# ChoiceStateEntered ChoiceStateExited … ParallelStateSucceeded SucceedStateEntered ExecutionSucceeded
# 3. Answer a waiting approval task (the token came in the officer's email)
aws stepfunctions send-task-success --task-token "$TASK_TOKEN" --task-output '{"approved":true}'
aws stepfunctions send-task-failure --task-token "$TASK_TOKEN" --error Rejected --cause "Trade licence expired"
# 4. After fixing the warehouse database, restart a failed order from the failed state
aws stepfunctions redrive-execution \
--execution-arn arn:aws:states:ap-southeast-1:111122223333:execution:order-example:order-5504
# { "redriveDate": "2026-10-28T11:20:05.771000+06:00" }
# 5. An Express workflow called synchronously (the API Gateway pattern)
aws stepfunctions start-sync-execution \
--state-machine-arn arn:aws:states:ap-southeast-1:111122223333:stateMachine:quote-express-example \
--input '{"restaurant":"R-12","area":"Dhanmondi"}'
# { "status": "SUCCEEDED", "output": "{\"price\":540,\"etaMinutes\":32}",
# "billingDetails": { "billedMemoryUsedInMB": 64, "billedDurationInMilliseconds": 300 } }
# 6. A user pool on the Essentials plan, email sign-in, optional MFA
aws cognito-idp create-user-pool --pool-name riders-example --user-pool-tier ESSENTIALS \
--username-attributes email --auto-verified-attributes email --mfa-configuration OFF
# { "UserPool": { "Id": "ap-southeast-1_Ab12Cd34E", "UserPoolTier": "ESSENTIALS", … } }
aws cognito-idp create-user-pool-client --user-pool-id ap-southeast-1_Ab12Cd34E \
--client-name rider-app --no-generate-secret \
--explicit-auth-flows ALLOW_USER_SRP_AUTH ALLOW_USER_PASSWORD_AUTH ALLOW_REFRESH_TOKEN_AUTH
# { "UserPoolClient": { "ClientId": "4exampleclientid0000000000", … } }
aws cognito-idp sign-up --client-id 4exampleclientid0000000000 \
--username rafi@example.com --password 'Long-Passphrase-2026!'
# { "UserConfirmed": false, "CodeDeliveryDetails": { "Destination": "r***@e***", "DeliveryMedium": "EMAIL" },
# "UserSub": "d1b2c3d4-5678-90ab-cdef-EXAMPLE11111" }
aws cognito-idp confirm-sign-up --client-id 4exampleclientid0000000000 \
--username rafi@example.com --confirmation-code 482913
# Password flow only for this CLI test; apps use SRP or managed login
aws cognito-idp initiate-auth --client-id 4exampleclientid0000000000 --auth-flow USER_PASSWORD_AUTH \
--auth-parameters USERNAME=rafi@example.com,PASSWORD='Long-Passphrase-2026!'
# { "AuthenticationResult": { "AccessToken": "eyJraWQiOi…", "ExpiresIn": 3600, "TokenType": "Bearer",
# "RefreshToken": "eyJjdHkiOi…", "IdToken": "eyJraWQiOi…" } }
# 7. An identity pool that trusts the user pool, with no guest access
aws cognito-identity create-identity-pool --identity-pool-name students_example \
--no-allow-unauthenticated-identities \
--cognito-identity-providers ProviderName=cognito-idp.ap-southeast-1.amazonaws.com/ap-southeast-1_Ab12Cd34E,ClientId=4exampleclientid0000000000
# { "IdentityPoolId": "ap-southeast-1:0a1b2c3d-1111-2222-3333-EXAMPLE44444", … }
aws cognito-identity set-identity-pool-roles \
--identity-pool-id ap-southeast-1:0a1b2c3d-1111-2222-3333-EXAMPLE44444 \
--roles authenticated=arn:aws:iam::111122223333:role/student-auth-example
# 8. Exchange the ID token for an identity ID, then for AWS credentials
aws cognito-identity get-id --identity-pool-id ap-southeast-1:0a1b2c3d-1111-2222-3333-EXAMPLE44444 \
--logins cognito-idp.ap-southeast-1.amazonaws.com/ap-southeast-1_Ab12Cd34E=$ID_TOKEN
# { "IdentityId": "ap-southeast-1:7c1e5f2a-aaaa-bbbb-cccc-EXAMPLE55555" }
aws cognito-identity get-credentials-for-identity \
--identity-id ap-southeast-1:7c1e5f2a-aaaa-bbbb-cccc-EXAMPLE55555 \
--logins cognito-idp.ap-southeast-1.amazonaws.com/ap-southeast-1_Ab12Cd34E=$ID_TOKEN
# { "IdentityId": "ap-southeast-1:7c1e5f2a-…",
# "Credentials": { "AccessKeyId": "ASIAEXAMPLE7Q2K", "SecretKey": "…", "SessionToken": "…",
# "Expiration": "2026-10-28T12:15:02+06:00" } }
Put those three values in AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN, then try aws s3 cp avatar.jpg s3://student-photos-example/ap-southeast-1:7c1e5f2a-aaaa-bbbb-cccc-EXAMPLE55555/avatar.jpg (allowed) and the same command with another student’s folder (AccessDenied).
#Summary
Key takeaways
- Step Functions orchestrates steps as a state machine written in Amazon States Language (ASL), designed visually in Workflow Studio. Exam phrases: “orchestrate multiple Lambda functions”, “coordinate microservices”, “state machine”.
- States: Task, Choice (always a Default), Wait, Parallel, Map (inline or Distributed over S3), Pass, Succeed, Fail. Retry (interval, backoff, max attempts) and Catch (to a recovery state) are configuration, not code; compensations make a saga; failed Standard executions can be redriven within 14 days.
- Integration patterns: Request Response, Run a job (
.sync), Wait for callback (.waitForTaskToken) for human approval, withSendTaskSuccess/SendTaskFailure, a timeout and heartbeats. Optimized integrations (Lambda, ECS, Batch, DynamoDB, SNS, SQS, Glue, SageMaker…), SDK integrations with over 220 services, HTTP Tasks, activities for EC2 and on-premises workers. - Standard: up to 1 year, exactly-once, 90-day history, callbacks and
.sync, priced per state transition (0.025 USD per 1,000). Express: up to 5 minutes, at-least-once (async) or at-most-once (sync), CloudWatch Logs only, priced per execution + GB-second; far cheaper for short high-volume work. Hours or days or manual approval → Standard. - Cognito user pool = authentication: user directory, sign-up / sign-in, verification, password reset, MFA, social / SAML / OIDC federation, managed login, Lambda triggers, JWTs (ID and access 1 h, refresh 30 days). Integrates with API Gateway authorizers and the ALB
authenticate-cognitoaction. Feature plans Lite / Essentials (default) / Plus (threat protection, compromised credentials). - Cognito identity pool = temporary AWS credentials through STS for direct S3 / DynamoDB access; sources: user pools, social, SAML, OIDC, developer identities; authenticated and guest roles;
${cognito-identity.amazonaws.com:sub}anddynamodb:LeadingKeysgive per-user folders and row-level security. - Cognito vs IAM: “hundreds of users”, “mobile users”, “authenticate with SAML” for an app → Cognito. IAM (Identity Center) is for people who manage AWS; never ship IAM keys in an app.
Answer on your own first, then read the explanation, even when you got it right.
Self-checkQuestion
A team chains five Lambda functions: each one invokes the next and waits for its result. What is the main problem Step Functions solves here?
Self-checkQuestion
In which language is a Step Functions state machine defined?
Self-checkQuestion
Which state type branches the workflow based on a value in the data, like an if statement?
Self-checkQuestion
A Task state has Retry with IntervalSeconds 3, BackoffRate 2 and MaxAttempts 3. The task fails every time. How long does Step Functions wait in total between attempts before giving up?
Self-checkQuestion
An order workflow charges the card, then the Reserve stock task fails even after all retries. The customer must not lose money. What should the state machine have?
Self-checkQuestion
A loan workflow must email a loan officer and continue only when the officer clicks Approve or Reject, which may take several days. Which design is correct?
Self-checkQuestion
A callback Task in a Standard workflow has no TimeoutSeconds, and the email with the token went to a spam folder. What happens?
Self-checkQuestion
A workflow must start an AWS Glue job and continue only when the job has finished, without writing polling code. Which integration pattern does the Task use?
Self-checkQuestion
An insurance company processes 5,000,000 claims-photo events a month. Each workflow has 3 steps, runs for about 400 ms, is idempotent and must be as cheap as possible. Which workflow type fits?
Self-checkQuestion
Calculate: a Standard workflow runs 200,000 times a month with 12 state transitions each. What is the monthly Step Functions bill in US East (0.025 USD per 1,000 transitions, 4,000 free)?
Self-checkQuestion
Calculate: an asynchronous Express workflow runs 2,000,000 times a month, each lasting 1 second at 64 MB. Using 1.00 USD per million requests and 0.06 USD per GB-hour, what is the bill?
Self-checkQuestion
A bank’s transfer workflow lasts about 90 seconds and calls a partner API that has no idempotency key: running a debit twice takes the money twice. Which type should it use?
Self-checkQuestion
A developer tries to create an Express workflow containing a Task with arn:aws:states:::sns:publish.waitForTaskToken. What happens?
Self-checkQuestion
Where do you see what happened inside an Express workflow execution that failed yesterday?
Self-checkQuestion
An online shop must check two million product photos in S3 every night with a Lambda function per photo, retries and a failure report. Which Step Functions feature fits best?
Self-checkQuestion
Which two statements about Standard workflows are true?
Choose 2
Self-checkQuestion
Which two ways let a state machine do work on servers or services without a Lambda function in between?
Choose 2
Self-checkQuestion
Which component of Amazon Cognito is a user directory that handles sign-up, sign-in, password reset and MFA, and returns JWTs?
Self-checkQuestion
A mobile app must let each signed-in user upload photos directly to S3, with no backend server and no long-term keys in the app. What should the architect use?
Self-checkQuestion
A university stores grades in DynamoDB with the identity pool identity ID as partition key. How can each student read only their own items using one shared IAM role?
Self-checkQuestion
An app offers a guest mode where visitors who have not created an account can read a public catalogue from S3. Which Cognito feature provides this?
Self-checkQuestion
A developer built only a Cognito user pool and sends the ID token in a header with PutObject to S3. The request fails with 403. What is the reason?
Self-checkQuestion
An internal dashboard runs on EC2 behind an Application Load Balancer and has no login code. The company wants staff to sign in through a Cognito user pool before any request reaches the instances, with the least development effort. What should it do?
Self-checkQuestion
Riders of an app call a REST API in API Gateway. The company wants API Gateway to reject requests without a valid user pool token, without writing authorizer code. What should it configure?
Self-checkQuestion
A logistics portal will serve several hundred staff from partner companies, each partner signing in with its own corporate SAML identity provider. Which is the best fit?
Self-checkQuestion
Calculate: an app has 40,000 monthly active users signing in directly to a user pool on the Essentials plan (10,000 MAUs free, then 0.015 USD per MAU). What is the monthly user pool bill?
Self-checkQuestion
A fintech wants its user pool to detect sign-ins that use passwords exposed in public breaches and to require extra verification for risky sign-ins. What is needed?
Self-checkQuestion
Which two statements about Cognito identity pools are true?
Choose 2
Self-checkQuestion
Which two statements about Cognito user pool tokens with default settings are correct?
Choose 2
Self-checkQuestion
In which two scenarios does the exam expect a Cognito identity pool rather than (or in addition to) only a user pool?
Choose 2