ข้ามไปเนื้อหา
Enterprise SSO

OIDC with AWS IAM Identity Center

Configure enterprise single sign-on (SSO) for Amazon Quick on desktop using OpenID Connect (OIDC) and AWS IAM Identity Center, so your users sign in with their corporate credentials.

Checked against official AWS documentation on 17 Oct 2026. The desktop app is generally available on macOS and Windows (since 9 Sep 2026).

Choose your approach

Amazon Quick Desktop enterprise sign-in requires an OIDC provider. The AWS-documented path is your existing IdP (Microsoft Entra ID, Google Workspace, Okta, or Ping Identity). The Amazon Cognito path is a field workaround.

Your organization already has an OIDC-compatible identity provider. AWS publishes setup guides for Microsoft Entra ID, Google Workspace, Okta, and Ping Identity (PingFederate and PingOne). This is the documented path — pick your identity provider to jump to its setup steps:

  Select your identity provider

Google Workspace: see the Google Workspace note in Step 1.

Or review the overview first (the AWS guide has four steps: IdP app, extension access, extension, distribute):

1

Step 1 — Create an OIDC application in your IdP

Register a public OIDC client (authorization code with PKCE).

2

Optional — Trusted Token Issuer

Not one of the four steps in the AWS desktop guide. Only if your design needs it (the Cognito workaround creates one).

3

Step 3 — Add extension access and create the extension

Register the OIDC endpoints in the Amazon Quick administration console, then create the extension.

4

Step 4 — Download, verify, and distribute

Test Continue with SSO and roll out to users.

Workaround (not an AWS-documented setup). The AWS desktop guides cover only an existing OIDC IdP. This Amazon Cognito + proxy pattern is the field workaround the AWS Thailand team uses. Amazon Quick Desktop sends the offline_access scope, which the Cognito + IAM Identity Center sign-in path does not accept, so a small proxy removes that scope before the request reaches the identity provider. Test it in your own account before you rely on it.

Use this path when you don't have an existing IdP: Amazon Quick with local users (no IAM Identity Center), or IAM Identity Center managing users directly with no external OIDC provider. You deploy Amazon Cognito as the OIDC provider using a sample CDK stack.

Why a proxy? The proxy strips offline_access from the /authorize request — so the Authorization Endpoint must point to the proxy, not the Cognito hosted UI. Cognito does not use the offline_access scope to control refresh tokens; it returns a refresh token for the authorization code grant (Cognito token endpoint).

Two ways to build the authorize proxy

The proxy has a single job: intercept the /authorize request, strip the unsupported offline_access scope (and optionally force identity_provider=IdentityCenter), then send the user on to Cognito. There are two ways to implement it — pick based on how much logic you need and how you plan to protect it.

The Authorization Endpoint points to a CloudFront path. A CloudFront Function on viewer-request rewrites the query string and returns the 302 at the edge — the Cognito origin is never contacted for /authorize.

  • Sub-millisecond at the edge, no cold start
  • Few moving parts: one distribution + one JS function
  • WAF attaches directly to the distribution
  • Low cost (~$0.10 / million requests)
AWS Thailand team's choice (not an AWS recommendation): the job is just "strip a scope + redirect", which a CloudFront Function handles. It is the team's tested reference deployment — see Reference deployment via CloudFront below.

AuthEndpoint = CloudFront URL · edge · no cold start

The Authorization Endpoint points to an API Gateway HTTP API. Each request invokes a Lambda that rewrites the query string and returns a 302 to the Cognito hosted UI. This is what the ready-made CDK stack deploys.

  • Full runtime — call AWS APIs, do lookups, crypto, async
  • Full CloudWatch Logs
  • Ready-made CDK stack, fast to deploy
Caveat: WAF cannot attach directly to an API Gateway HTTP API — you must front it with CloudFront or switch to a REST API. Choose this option when your logic exceeds what a CloudFront Function allows.

AuthEndpoint = API Gateway URL · full runtime · regional

Side-by-side comparison

DimensionOption 1 — API Gateway + LambdaOption 2 — CloudFront Function
Where code runsRegional (one Region)Edge (global PoPs)
LatencyLambda cold start + regional round tripSub-millisecond, no cold start
Origin contacted for /authorizeYes — request reaches the endpointNo — 302 returned at the edge
Host-header / origin-request-policyMust be handledNot a concern (origin not used)
Moving partsAPI Gateway + Lambda + IAM roleOne CloudFront distribution + one JS function
Compute limitsFull runtime — call AWS APIs, crypto, asyncVery limited: ≤10 KB code, ~1 ms CPU, no network calls, JS subset (cloudfront-js-2.0)
LoggingFull CloudWatch LogsLimited
Cost per requestLambda + API Gateway requestsLower — CloudFront Function ~$0.10 / million
Best forLogic beyond a simple rewrite (lookups, calling other APIs)A pure 302 query-string rewrite (this exact use case)

What both options share

  • Only /authorize is proxied — Token, JWKS and Issuer endpoints point to Cognito directly (the token exchange is a POST and must reach Cognito).
  • Refresh tokens still work without offline_access — Cognito issues them from the app client's refresh-token expiration, independent of the scope.
  • Federation is forced through IAM Identity Center by adding identity_provider=IdentityCenter to the Cognito authorization request. If this design uses a Trusted Token Issuer, it is for trusted identity propagation and token exchange, not for routing the sign-in.

Adding AWS WAF

Key limitation: AWS WAF attaches to CloudFront, API Gateway REST API, ALB, AppSync, Cognito user pool, App Runner and Amplify — but not to an API Gateway HTTP API. The ready-made stack uses an HTTP API, so WAF cannot be attached to it directly.
 Option 1 (API Gateway HTTP API)Option 2 (CloudFront)
Attach WAF directly?No — HTTP API unsupportedYes — on the distribution
Web ACL scope / RegionNeed a REST API (REGIONAL) or front it with CloudFrontCLOUDFRONT scope — create in us-east-1
Evaluation orderWAF → API Gateway → LambdaWAF runs before the CloudFront Function

Options for the HTTP-API path: front it with CloudFront and attach WAF there; switch to a REST API to use WAF and resource policies; or keep the HTTP API and use IAM authorization, a JWT/Lambda authorizer, and throttling (HTTP APIs do not support resource policies).

Protect Cognito too: because Token/JWKS go straight to Cognito, attach a WAF Web ACL to the Cognito user pool as well (rate-limit login attempts and filter unwanted requests). For credential-stuffing and account-takeover protection, evaluate AWS WAF Fraud Control ATP or Amazon Cognito threat protection separately. Managed rules the team uses on either path: AWSManagedRulesCommonRuleSet, AWSManagedRulesAmazonIpReputationList, plus a rate-based rule.
Team's choice: for this narrow "strip a scope" task, the AWS Thailand team uses Option 2 (CloudFront Function): simpler, faster, cheaper, and WAF attaches to the distribution. Option 1 (API Gateway + Lambda) is the alternative when you need richer logic than a CloudFront Function allows. Neither option is an AWS recommendation. The step-by-step below follows the sample CDK stack (Option 1); the Reference deployment via CloudFront section covers Option 2.

What the stack deploys

  • Amazon Cognito User Pool with a hosted UI domain and a public app client
  • Secrets Manager secret with a generated temporary password for new users
  • Trusted Token Issuer in IAM Identity Center (auto-discovered; skipped if no IDC instance exists)
  • API Gateway HTTP API + Lambda proxy that strips the unsupported offline_access scope

Prerequisites

AWS account with an active Amazon Quick subscription (Enterprise account; home Region must be one where the desktop app is available); Node.js 18+, AWS CDK CLI, Python 3.12+ with boto3, and configured AWS credentials; the desktop application installed.

Step 1 — Deploy

cd proxy npm install cdk deploy

API Gateway HTTP APIs do not support resource policies. To restrict the authorize endpoint by source IP, front the HTTP API with CloudFront and AWS WAF, or switch to a REST API and use AWS WAF or a resource policy.

Retrieve stack outputs:

aws cloudformation describe-stacks \ --stack-name QuickDesktopCognitoProxyStack \ --query "Stacks[0].Outputs" --output table

Step 2 — Sync users

Copy users into the Cognito User Pool (the script reads the pool ID and temporary password from the stack and prompts before creating each user).

python3 scripts/sync_users.py --source quicksight # local users python3 scripts/sync_users.py # IAM Identity Center

Step 3 — Configure extension access

In the Amazon Quick administration console, choose Manage account → Permissions → Extension access and enter the stack outputs. Then, in the Amazon Quick console left navigation, choose Extensions (under More if you don't see it) and create the extension.

FieldStack output
Trusted Token Issuer ARN (IDC only)TtiArn
Aud claimClientId
Issuer URLIssuerUrl
Authorization EndpointAuthEndpoint (API Gateway)
Token EndpointTokenEndpoint
JWKS URIJwksUri
Client IDClientId

Step 4 — Sign in

Launch the desktop app and choose Continue with SSO. Sign in with your username or email and the temporary password — you'll be prompted to set a new password on first login.

Security considerations

Protect the API Gateway: An HTTP API has a public endpoint by default. To use AWS WAF, front it with CloudFront or switch to a REST API. For the HTTP API itself, use IAM authorization, a JWT/Lambda authorizer, and throttling as appropriate. The sync_users.py script is a manual stop-gap. For production, use an organization-approved provisioning process and test the full user lifecycle end to end.

Troubleshooting

IssueCause / fix
redirect_mismatchCallback URL must be http://localhost:18080 (the stack sets this automatically).
invalid_scopeAuthorization Endpoint must point to the API Gateway (AuthEndpoint), not the Cognito hosted UI.
User not foundThe email in Cognito must exactly match the user's email in Amazon Quick.
Stale config after changesClear cached profiles in ~/.quickwork/ (see below).
Clearing the ~/.quickwork cache (team observation): AWS documents ~/.quickwork/ (macOS) and %USERPROFILE%\.quickwork\ (Windows) as the folder for local settings. The team found the OIDC config cached in ~/.quickwork/profiles.json, surviving reinstalls. After reconfiguring extension access, remove the cached enterprise profile entry so the app picks up the new values.

This Cognito approach is a field workaround for environments without an IdP and is not an AWS-documented setup. For deployments with an existing IdP, use the I have an IdP tab. For a fully deployed CloudFront-based variant, see Reference deployment — Cognito + Identity Center via CloudFront below. See also the public enterprise setup guide.

Overview — How enterprise sign-in works

Applies to: Enterprise Edition (if you use a Free or Plus account, this setup does not apply) · Intended audience: System administrators. Source: AWS Documentation

The Amazon Quick desktop application uses the OIDC protocol to authenticate users. When a user chooses Continue with SSO, a browser window opens to Amazon Quick, which identifies your configured identity provider and redirects to your IdP's authorization endpoint. To identify the IdP, the browser needs an active Amazon Quick web session; if there is none, the browser asks the user to sign in to Amazon Quick first. The app then exchanges the authorization code for tokens using Proof Key for Code Exchange (PKCE). Amazon Quick validates the token and maps the user to an identity in your account — the email in your IdP must exactly match the user's email in Amazon Quick.

1. Continue with SSO

User chooses Continue with SSO in the desktop app.

2. Redirect to IdP

Browser opens your IdP authorization endpoint.

3. Auth code + PKCE

Code is exchanged for tokens (no client secret).

4. Validate & map

Quick validates the token and matches the email.

Region requirement: The Amazon Quick account's home region (identity region) must be a supported Region. Amazon Quick on desktop is available for Enterprise accounts in Regions that support the full Amazon Quick feature set; Regions with Amazon Quick Sight capabilities only do not include desktop. The desktop app is available in 7 Regions: US East (N. Virginia), US West (Oregon), Asia Pacific (Sydney), Asia Pacific (Tokyo), Europe (Ireland), Europe (London), and Europe (Frankfurt) — not Singapore or Thailand. All identity types are supported: IAM Identity Center, IAM federation, and native Amazon Quick (username/password).
Token signing: Your IdP must sign ID tokens with an asymmetric algorithm (RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512). HMAC (HS256/HS384/HS512) and unsigned tokens are rejected.

Prerequisites

Verify the following before you begin.

RequirementDetail
AWS account & subscriptionAn AWS account with an active Amazon Quick subscription (Enterprise account). The home region (identity region) must be a supported Region where the desktop app is available (see the Region note above).
Administrator accessAdministrator access to your Amazon Quick account.
IdP permissionsAccess to your identity provider with permissions to create OIDC application registrations.
Network accessIn restricted networks, allow the required Amazon Quick and identity provider domains. See Network access and required domains.
IAM Identity Center (optional)The AWS desktop guide does not include a Trusted Token Issuer (TTI) step. The Cognito workaround on this page creates one. See Identity Center below.

Step 1 — Create an OIDC application in your IdP

Register a public OIDC client (authorization code flow with PKCE, no client secret — except Google Workspace, see below). Grant offline_access (Entra ID, Okta, Ping) so the IdP issues refresh tokens; without it, users must re-authenticate frequently.

Common settings

Redirect URI: http://localhost:18080
Client type: Public / Native (no secret)
Grant types: Authorization Code + Refresh Token
PKCE: Required (S256)
Scopes: openid email profile offline_access

Refresh tokens

Entra ID: grant offline_access.
Okta: enable Refresh Token grant + offline_access.
Ping: enable Refresh Token grant + offline_access. For PingFederate also enable Return ID Token On Refresh Grant.
Google Workspace: no extra scope; Quick adds access_type=offline automatically.

Google Workspace (from the AWS guide): In Google Cloud Console create an OAuth client ID with application type Desktop app, set the consent screen User type to Internal, and add scopes openid, email, profile. Endpoints: Issuer https://accounts.google.com; Authorization https://accounts.google.com/o/oauth2/v2/auth; Token https://oauth2.googleapis.com/token?client_secret=<CLIENT_SECRET> (the client secret is appended as a query parameter); JWKS https://www.googleapis.com/oauth2/v3/certs. Full steps: Google Workspace guide.
1

New registration

Azure portal → Microsoft Entra ID → App registrations → New registration. Name: Amazon Quick Desktop; Supported account types: Single tenant; Redirect URI platform: Public client/native (mobile & desktop); Redirect URI: http://localhost:18080. Choose Register.

2

Note the IDs

On the Overview page, note the Application (client) ID and Directory (tenant) ID.

3

API permissions

Add Microsoft Graph → Delegated permissions: openid, email, profile, offline_access. Grant admin consent if required.

4

Authentication settings

Under Advanced settings, leave Allow public client flows set to No. Verify http://localhost:18080 is listed under Mobile and desktop applications. Save. (Entra ID enforces PKCE automatically for public clients.)

5

Token configuration (required)

Token configuration → Add optional claim → token type ID → email. Each user must also have the Mail attribute filled in their Entra ID profile; the UPN alone is not enough.

The Issuer URL must include /v2.0 (do not use the Authority URL from the Endpoints panel). If your app has custom signing keys from claims mapping, append ?appid=<CLIENT_ID> to the JWKS URI.

FieldValue (replace <TENANT_ID>)
Issuer URLhttps://login.microsoftonline.com/<TENANT_ID>/v2.0
Authorization endpointhttps://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize
Token endpointhttps://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token
JWKS URIhttps://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys
1

Create App Integration

Okta Admin Console → Applications → Applications → Create App Integration. Sign-in method: OIDC - OpenID Connect; Application type: Native Application.

2

Configure

Name: Amazon Quick Desktop; Grant type: Authorization Code + Refresh Token; Sign-in redirect URI: http://localhost:18080; assign to the appropriate users/groups. Save and note the Client ID.

3

Verify settings

On the General tab confirm: application type Native, client authentication None (public client), PKCE Required, and http://localhost:18080 under LOGIN. Quick requests openid, profile, email, offline_access at sign-in.

FieldValue (replace <OKTA_DOMAIN>, e.g. your-org.okta.com — not the -admin subdomain)
Issuer URLhttps://<OKTA_DOMAIN>
Authorization endpointhttps://<OKTA_DOMAIN>/oauth2/v1/authorize
Token endpointhttps://<OKTA_DOMAIN>/oauth2/v1/token
JWKS URIhttps://<OKTA_DOMAIN>/oauth2/v1/keys
1

Add client

Applications → OAuth → Clients → Add Client. Enter a unique Client ID; Name: Amazon Quick Desktop; Client Authentication: None; Redirection URI: http://localhost:18080.

2

Grants, PKCE, scopes

Allowed Grant Types: Authorization Code + Refresh Token; select Require PKCE; grant scopes openid, email, profile, offline_access. Save and note the Client ID.

3

OIDC policy

Applications → OAuth → OpenID Connect Policy Management. Select Return ID Token On Refresh Grant, and verify the email claim is in the Attribute Contract and mapped for both initial auth and refresh grants.

FieldValue (replace <PINGFEDERATE_HOST>)
Issuer URLhttps://<PINGFEDERATE_HOST>
Authorization endpointhttps://<PINGFEDERATE_HOST>/as/authorization.oauth2
Token endpointhttps://<PINGFEDERATE_HOST>/as/token.oauth2
JWKS URIhttps://<PINGFEDERATE_HOST>/pf/JWKS
1

Create application

PingOne admin console → Applications → +. Name: Amazon Quick Desktop; Application Type: Native. Save.

2

Configuration

Response Type: Code; Grant Type: Authorization Code + Refresh Token; PKCE Enforcement: S256; Redirect URIs: http://localhost:18080; Token Endpoint Authentication Method: None. Save.

3

Scopes, attributes, enable

Resources tab (separate from the Configuration tab): add openid, email, profile, offline_access — PingOne grants only openid by default, and skipping this causes "User info request failed (HTTP 401)". Attribute Mappings: map email to the user's email. Toggle the app to Enabled. Note the Client ID and Environment ID. For JWKS use /as/jwks, not /.well-known/jwks.json.

FieldValue (replace <ENV_ID>; domain varies by region)
Issuer URLhttps://auth.pingone.com/<ENV_ID>/as
Authorization endpointhttps://auth.pingone.com/<ENV_ID>/as/authorize
Token endpointhttps://auth.pingone.com/<ENV_ID>/as/token
JWKS URIhttps://auth.pingone.com/<ENV_ID>/as/jwks

Optional — Trusted Token Issuer in IAM Identity Center

Not part of the AWS desktop setup guide, which has four steps (IdP app, extension access, extension, distribute) for every identity type, including IAM Identity Center. The Cognito workaround on this page creates a TTI; add one only if your design needs it. A Trusted Token Issuer (TTI) lets IAM Identity Center trust OIDC tokens from an external issuer (trusted identity propagation). Source: AWS Documentation

1

Open Settings → Authentication

In the IAM Identity Center console, choose Settings, then the Authentication tab. Under Trusted token issuers, choose Create trusted token issuer.

2

Issuer URL (OIDC discovery)

For Issuer URL, specify the IdP's OIDC discovery URL up until and without .well-known/openid-configuration. It must match the iss claim in the issued tokens. The discovery endpoint must be reachable on ports 80 and 443 only.

3

Map attributes

Under Map attributes, choose an Identity provider attribute (a claim in the token, e.g. email) and the corresponding IAM Identity Center attribute used to look up a single user in the Identity Center directory.

4

Create & notify

Enter a Trusted token issuer name, then choose Create trusted token issuer. Notify the application administrator so they can select it and configure token exchange (including the Aud claim value for the receiving AWS service).

Aud (audience) claim: The TTI places an Aud claim in the token to indicate the receiving AWS service. The external IdP administrator provides this value to the AWS service administrator, who configures token exchange to accept it.
Editing a TTI may cause users to lose access to applications that use it. Coordinate with application administrators before changing issuer URL, attribute mappings, or tags.

Step 3 — Add extension access and create the extension

Register the OIDC endpoints from Step 1 so the desktop application can authenticate. Both parts are required.

1

Add extension access

Sign in to the Amazon Quick administration console and choose Manage account → under Permissions, Extension access → Add extension access. Under Select Service, select Amazon Quick (Desktop application for Quick) and choose Next.

2

Enter the OIDC details

Fill in the fields from the table below with values from Step 1, then choose Add.

3

Create the extension

In the Amazon Quick console left navigation, choose Extensions (choose More if you don't see it) → Add extension. Select the Desktop application for Quick extension access you created, choose Next, then Create. Without this step users see "Enterprise sign-in for Quick Desktop has not been configured for this account." It is a one-time, account-level action.

FieldValue
NameA name for this extension access (for example, QuickDesktop-access); alphanumeric characters and hyphens only, no spaces
Description(Optional) A description
Issuer URLThe exact OIDC issuer URL from Step 1, including any required path suffix
Authorization EndpointThe OIDC authorization endpoint from Step 1
Token EndpointThe OIDC token endpoint from Step 1
JWKS URIThe JSON Web Key Set URI from Step 1
Client IDThe OIDC client identifier from Step 1
Cannot be edited: Verify all values before choosing Add. Extension access configuration cannot be edited after creation — if a value is wrong, delete it and create a new one.

Step 4 — Download, verify, and distribute

Confirm the configuration, then roll out to your users.

1

Download and test Continue with SSO

In the Amazon Quick console choose Extensions, select the Quick Desktop extension, open the more options menu (...) and choose Download for Windows or Download for Mac. Install the app, choose Continue with SSO on the sign-in screen, optionally select your AWS Region (or Dynamic), and authenticate with your corporate credentials.

2

Fix any incorrect values

If sign-in fails, verify the Step 3 values against the Step 1 endpoints. If a value is wrong, delete the extension access under Permissions → Extension access and repeat Step 3.

3

Distribute to users

Direct your users to the installation guide. Users choose Continue with SSO; no per-user configuration is required. For silent fleet installs see Managed deployment configuration (single-user Windows silent install: .\Amazon-Quick-Setup.exe /S).

Reference deployment — Cognito + Identity Center via CloudFront

Workaround (not an AWS-documented setup). This is the AWS Thailand team's field pattern, not an AWS-documented or AWS-recommended configuration. Amazon Quick Desktop sends the offline_access scope, which this Cognito + IAM Identity Center path does not accept, so the CloudFront Function removes it before the request reaches the identity provider. For the documented path, use your IdP's AWS guide (Entra ID, Google Workspace, Okta, Ping Identity).

A tested variant of the Cognito path. Instead of an API Gateway + Lambda proxy, a single CloudFront Function returns a 302 at the edge — it strips offline_access and forces federation through IAM Identity Center. The origin is never hit for /authorize, so there are no Host-header or origin-request-policy concerns. All identifying values below are masked.

End-to-end trust chain

Amazon Quick Desktop Consumer account · public client + PKCE · callback http://localhost:18080 AuthEndpoint = CloudFront /oauth2/authorize CloudFront Function — viewer-request strip offline_access · add identity_provider=IdentityCenter returns HTTP 302 at the edge (origin not contacted) HTTP 302 redirect (browser follows Location) Amazon Cognito user pool OIDC provider to Amazon Quick · issues tokens SAML federation (identity_provider=IdentityCenter) IAM Identity Center Actual authentication · custom-SAML app · identity store Cognito-issued JWT Trusted identity propagation (Trusted Token Issuer) IAM Identity Center trusts Cognito-issued JWTs via a Trusted Token Issuer (OIDC_JWT). The Amazon Quick (QuickSight) application then receives token-exchange / trusted identity propagation.

Authorize requests are rewritten at the CloudFront edge; Token / JWKS / Issuer go straight to Cognito.

Building blocks

CloudFront Function (strip offline_access + force IdC)

// cloudfront-js-2.0 | event: viewer-request | path: /oauth2/authorize function handler(event) { var COGNITO_AUTHORIZE = 'https://us-east-1XXXXXXXXX.auth.us-east-1.amazoncognito.com/oauth2/authorize'; var qs = event.request.querystring; // Values arrive URL-encoded; scope tokens are separated by %20 or +. // Strip "offline_access" while preserving the original separator. if (qs.scope && qs.scope.value) { var raw = qs.scope.value; var sep = raw.indexOf('%20') >= 0 ? '%20' : (raw.indexOf('+') >= 0 ? '+' : ' '); var toks = raw.split(sep); var kept = []; for (var i = 0; i < toks.length; i++) { if (toks[i] && toks[i] !== 'offline_access') kept.push(toks[i]); } qs.scope = { value: kept.join(sep) }; } // Force sign-in straight through IAM Identity Center. qs['identity_provider'] = { value: 'IdentityCenter' }; var pairs = []; for (var key in qs) { var item = qs[key]; if (item.multiValue) { for (var j = 0; j < item.multiValue.length; j++) pairs.push(key + '=' + item.multiValue[j].value); } else { pairs.push(key + '=' + item.value); } } return { statusCode: 302, statusDescription: 'Found', headers: { 'location': { value: COGNITO_AUTHORIZE + '?' + pairs.join('&') }, 'cache-control': { value: 'no-store' } } }; }

What to set in Amazon Quick (Extension access)

FieldValue
Authorization Endpointhttps://dXXXXXXXXXXXXX.cloudfront.net/oauth2/authorize — CloudFront
Token Endpointhttps://us-east-1XXXXXXXXX.auth.us-east-1.amazoncognito.com/oauth2/token — Cognito (direct)
Issuer URLhttps://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX — Cognito (direct)
JWKS URI.../us-east-1_XXXXXXXXX/.well-known/jwks.json — Cognito (direct)
Aud claim / Client ID<PUBLIC_CLIENT_ID>

Verify (curl against the live distribution)

$ curl -i "https://dXXXXXXXXXXXXX.cloudfront.net/oauth2/authorize?\ client_id=<PUBLIC_CLIENT_ID>&response_type=code&\ scope=openid+email+profile+offline_access&\ redirect_uri=http://localhost:18080&\ code_challenge=...&code_challenge_method=S256" HTTP/2 302 x-cache: FunctionGeneratedResponse from cloudfront cache-control: no-store location: https://us-east-1XXXXXXXXX.auth.us-east-1.amazoncognito.com/oauth2/authorize?... &scope=openid+email+profile&identity_provider=IdentityCenter

→ offline_access removed, IAM Identity Center federation forced, and code_challenge (PKCE) preserved.

Why a 302 function instead of an API Gateway proxy? The CloudFront Function returns the redirect at the edge (FunctionGeneratedResponse), so the Cognito origin is never contacted for /authorize — no Host-header rewriting, no origin-request-policy needed, sub-millisecond, and no Lambda cold start.
Refresh tokens still work without offline_access: Cognito does not use the offline_access scope to control refresh tokens; it returns one for the authorization code grant, and you set the lifetime with the app client's refresh-token validity (Cognito token endpoint). Stripping the scope avoids invalid_scope without shortening sessions.
Point Token / JWKS / Issuer at Cognito directly — not CloudFront: the distribution allows only GET/HEAD and the function 302-redirects every request; the token exchange is a POST and must reach Cognito.
Forcing identity_provider=IdentityCenter routes every sign-in through IAM Identity Center (no direct local Cognito users). Add a separate path if you need a break-glass local admin.
For production: add a custom domain (ACM certificate in us-east-1) and an AWS WAF Web ACL to the distribution. The default *.cloudfront.net domain is fine for testing.

Troubleshooting

Common issues and resolutions (from the AWS troubleshooting guide). Tip: you can export application logs from the sign-in screen.

SymptomResolution
redirect_mismatch errorVerify the redirect URI in your IdP is exactly http://localhost:18080 and configured as a public client / native platform.
User not found after sign-inThe token must contain the email claim (Entra ID: add the email optional claim and fill the user's Mail attribute) and it must exactly match a provisioned Amazon Quick user. Email matching is case-sensitive.
Token validation failureVerify the issuer URL in the extension access matches the IdP's OIDC issuer exactly, and that the IdP signs ID tokens with a supported asymmetric algorithm (not HMAC).
Invalid issuer (Entra ID)The Issuer URL must include /v2.0. Delete the extension access and recreate it with the correct value.
Enterprise sign-in not configured for this accountThe extension access exists but the extension was not created. Create it on the Extensions page (Step 3).
User info request failed (HTTP 504)Transient backend timeout. Sign in to Amazon Quick in the web browser first, then retry desktop sign-in; check network access to the required domains.
Access blocked: app not verified (Google Workspace)Set the OAuth consent screen User type to Internal.
Consent / permission errors (Entra ID)Grant admin consent for the required API permissions in the Azure portal (app registration → API permissions).
Session expires frequentlyEnsure the IdP issues refresh tokens: Entra ID needs offline_access; Okta and Ping need the Refresh Token grant and offline_access; Google is handled automatically. For PingFederate, also enable Return ID Token On Refresh Grant.
User info request failed (HTTP 401) (PingOne)Add email, profile, offline_access on the application's Resources tab.
Token validation failure with PingOne JWKSUse the /as/jwks path, not /.well-known/jwks.json.
Application not enabled (PingOne)If auth fails before reaching the login page, verify the application toggle is set to Enabled.
Missing email claim after refresh (PingFederate)Verify the email claim is in the OIDC policy Attribute Contract and mapped for both initial auth and refresh grants.

References

Official AWS documentation used on this page.