491 lines
26 KiB
Markdown
491 lines
26 KiB
Markdown
# Cognito
|
|
|
|
**Protocol:** JSON 1.1 (`X-Amz-Target: AWSCognitoIdentityProviderService.*`)
|
|
**Endpoint:** `POST http://localhost:4566/`
|
|
|
|
Floci serves pool-specific discovery and JWKS endpoints, plus a relaxed OAuth token endpoint, so local clients can mint and validate Cognito-like access tokens against RS256 signing keys.
|
|
|
|
`CreateUserPool` supports overiding several values using user-pool tags **only** at creation time:
|
|
* `floci:override-id`, to pin the resulting `UserPool.Id`. Because a pinned id is caller-chosen it can be reused, which AWS never does. `DeleteUserPool` therefore deletes everything the pool owns (users, groups, app clients, resource servers, revoked token records and outstanding verification codes) so a pool recreated on the same id starts empty rather than inheriting the deleted pool's password hashes and client secrets.
|
|
* `floci:override-cognito-client-id`
|
|
* set to `use-name` to use the client name as client ID.
|
|
* set to `append-to-name:-somestring` to append a string to the client name to be used as client ID.
|
|
* set to `prepend-to-name:somestring-` to prepend a string to the client name to be used as client ID.
|
|
* `floci:override-cognito-client-secret`, to set the secret for all clients created in this userpool.
|
|
|
|
Floci strips reserved `floci:*` tags from stored and returned `UserPoolTags` on both create and update paths, so the tag namespace acts as an input-only control channel and is never persisted as user-visible metadata.
|
|
|
|
Standalone `TagResource` rejects reserved `floci:*` keys. `ListTagsForResource` and `UntagResource` operate on the persisted user-pool tag map.
|
|
|
|
An action given a user pool ID that does not resolve returns `ResourceNotFoundException` with the live service's wording, `User pool <poolId> does not exist.`, so tooling that matches Cognito error text behaves the same way locally.
|
|
|
|
## Supported Actions
|
|
|
|
### User Pools
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateUserPool | Creates a local user pool, applying supported `floci:*` creation-time overrides from tags. |
|
|
| DescribeUserPool | Returns the stored user pool configuration. |
|
|
| ListUserPools | Lists local user pools visible in the request region. |
|
|
| UpdateUserPool | Updates mutable user pool settings and persisted user-pool tags. |
|
|
| DeleteUserPool | Deletes a local user pool and everything it owns: users, groups, app clients, resource servers, identity providers, revoked tokens and verification codes. Refused with `InvalidParameterException` while `DeletionProtection` is `ACTIVE` (switch it to `INACTIVE` with `UpdateUserPool` first, as on AWS) or while a domain is still configured. |
|
|
| GetUserPoolMfaConfig | Returns the pool's MFA mode and, once configured, its software-token setting. |
|
|
| SetUserPoolMfaConfig | Sets `MfaConfiguration` (`OFF`/`ON`/`OPTIONAL`) and `SoftwareTokenMfaConfiguration`. An absent `MfaConfiguration` means `OFF`, and turning MFA off drops the factor configuration with it. Validation follows the live service: `OFF` alongside a software-token, email or SMS factor is rejected, and `ON`/`OPTIONAL` with none of those three is rejected, in both cases on the member being present, not on its `Enabled` value. `WebAuthnConfiguration` sits outside both rules, as it does in AWS. SMS, email and WebAuthn configurations are validated and not stored: Floci cannot deliver those factors, so keeping the config would imply a capability it does not have. |
|
|
|
|
### User Pool Tags
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| TagResource | Adds user-visible tags to a user pool and rejects reserved `floci:*` tag keys. |
|
|
| UntagResource | Removes tags from a user pool's persisted tag map. |
|
|
| ListTagsForResource | Returns the persisted user-pool tags. |
|
|
|
|
### User Pool Clients
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateUserPoolClient | Creates an app client for a user pool, including optional generated secret handling. |
|
|
| DescribeUserPoolClient | Returns the stored app client configuration. |
|
|
| ListUserPoolClients | Lists app clients for a user pool. |
|
|
| DeleteUserPoolClient | Deletes an app client from a user pool. |
|
|
|
|
### Resource Servers
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateResourceServer | Registers a resource server and scopes for a user pool. |
|
|
| DescribeResourceServer | Returns a registered resource server. |
|
|
| ListResourceServers | Lists resource servers for a user pool. |
|
|
| UpdateResourceServer | Updates a resource server's name and scopes. |
|
|
| DeleteResourceServer | Deletes a resource server from a user pool. |
|
|
|
|
### Identity Providers
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateIdentityProvider | Registers a federated identity provider on a user pool. |
|
|
| DescribeIdentityProvider | Returns a registered identity provider. |
|
|
| ListIdentityProviders | Lists a user pool's providers as name/type/date summaries. |
|
|
| UpdateIdentityProvider | Updates a provider's details, attribute mapping or identifiers. |
|
|
| DeleteIdentityProvider | Deletes an identity provider from a user pool. |
|
|
|
|
Providers can be used for generic OIDC authorization-code sign-in. Floci routes the
|
|
AWS-shaped `/oauth2/authorize` and `/oauth2/idpresponse` endpoints to the configured local
|
|
OIDC provider, exchanges the returned code, provisions or reconciles the federated user,
|
|
and issues a Cognito authorization code for the registered callback.
|
|
|
|
Only `ProviderType=OIDC` is supported by this flow. Floci does not provide a built-in hosted
|
|
UI and does not implement social providers such as Google, Facebook, Login with Amazon or
|
|
SignInWithApple.
|
|
|
|
Two deliberate divergences from AWS, both consequences of not calling out to a third
|
|
party:
|
|
|
|
- **No create-time validation of `ProviderDetails`.** AWS resolves an OIDC provider's
|
|
`oidc_issuer` discovery document while handling `CreateIdentityProvider`, and rejects
|
|
the call when it is unreachable. Floci stores `ProviderDetails` opaquely and makes no
|
|
outbound request, so it also does not enforce the per-provider-type required keys.
|
|
- **No injected provider defaults.** AWS adds keys such as
|
|
`attributes_url_add_attributes` to an OIDC provider's stored details; Floci returns
|
|
only what was supplied.
|
|
|
|
`AttributeMapping` and `IdpIdentifiers` follow AWS's update semantics: a member the
|
|
request omits is left unchanged, and an explicitly empty map or list is what clears it.
|
|
`IdpIdentifiers` is echoed by `CreateIdentityProvider` and `UpdateIdentityProvider` only
|
|
when the request supplied it, whatever the stored value, while `DescribeIdentityProvider`
|
|
always returns it.
|
|
|
|
### User Pool Domains
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateUserPoolDomain | Creates a Cognito prefix domain, or a custom domain when `CustomDomainConfig.CertificateArn` is given. As on AWS, the certificate must exist in ACM in us-east-1 with status `ISSUED`; the domain is listed under the certificate's `InUseBy` until it is deleted. |
|
|
| DescribeUserPoolDomain | Returns a domain's description, including `CloudFrontDistribution` for custom domains. |
|
|
| UpdateUserPoolDomain | Replaces a custom domain's certificate or changes the managed login version in place. The domain keeps its `CloudFrontDistribution`, and its `InUseBy` entry moves to the new certificate. |
|
|
| DeleteUserPoolDomain | Deletes a domain from its user pool. |
|
|
|
|
#### Custom domains
|
|
|
|
A domain created with `CustomDomainConfig` answers the OAuth endpoints on that host, as on AWS:
|
|
|
|
```
|
|
POST https://auth.example.localhost.floci.io/oauth2/token
|
|
GET https://auth.example.localhost.floci.io/oauth2/userInfo
|
|
```
|
|
|
|
Requests are matched on the `Host` header, so the name must resolve to Floci (any
|
|
`*.localhost.floci.io` does) and, for `https`, TLS must be enabled. The domain pins its user pool and
|
|
the account that created it, since these requests carry no AWS credential: a `client_id` from
|
|
another pool is refused with `invalid_client`, and an access token issued by another pool with
|
|
`invalid_token`. Domain names are unique across all accounts, as on AWS. The pool's `openid-configuration` advertises the custom-domain
|
|
URLs when one exists. Prefix domains (`<prefix>.auth.<region>.amazoncognito.com`) are stored but not
|
|
routed, since that hostname never reaches Floci. `/login` and `/logout` are not served on any host.
|
|
|
|
With TLS enabled, a custom domain (`CustomDomainConfig` set) is added to Floci's server
|
|
certificate as soon as it is created, so `https://<domain>` verifies without a restart; see
|
|
[TLS](../configuration/tls.md) for the accepted suffixes. A prefix domain is served under
|
|
`amazoncognito.com` on AWS, not by Floci, and is left alone.
|
|
|
|
### Log Delivery
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| SetLogDeliveryConfiguration | Replaces a user pool's log delivery configuration. |
|
|
| GetLogDeliveryConfiguration | Returns a user pool's log delivery configuration. |
|
|
|
|
`LogLevel` accepts `ERROR` or `INFO`, and `EventSource` accepts `userNotification` or
|
|
`userAuthEvents`. `LogConfigurations` holds at most 2 entries, and an event source may
|
|
appear only once across them. Each entry must name a destination:
|
|
`CloudWatchLogsConfiguration`, `FirehoseConfiguration` or `S3Configuration`, and a request
|
|
that omits one is rejected the way AWS rejects it. `Set` replaces the whole list rather
|
|
than merging, so an empty `LogConfigurations` is what clears it, and `Get` always returns
|
|
the member, as `[]` when nothing is configured.
|
|
|
|
The length and enum checks run before the pool is looked up, so an oversized or malformed
|
|
request naming a pool that does not exist reports the request problem rather than
|
|
`ResourceNotFoundException`, and every violation of them is reported in one message.
|
|
|
|
Floci stores the configuration and never delivers anything to the destination: the log
|
|
group, delivery stream or bucket is not written to, and is not required to exist. Two
|
|
further divergences, both deliberate:
|
|
|
|
- **No pricing-tier gate.** AWS refuses `userAuthEvents` on a pool in the `ESSENTIALS`
|
|
tier with `FeatureUnavailableInTierException`; Floci accepts either event source
|
|
whatever `UserPoolTier` says.
|
|
- **No destination validation.** AWS checks the ARN it is handed; Floci stores it as
|
|
given.
|
|
|
|
### Admin User Management
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| AdminCreateUser | Creates or resends setup for a user in a user pool. |
|
|
| AdminGetUser | Returns a user's stored attributes and status. |
|
|
| AdminDeleteUser | Deletes a user from a user pool. |
|
|
| AdminSetUserPassword | Sets a user's password and permanent-password status. |
|
|
| AdminUpdateUserAttributes | Updates attributes for a user in a user pool. |
|
|
| AdminLinkProviderForUser | Links an external IdP identity to an existing user's `identities` attribute. |
|
|
|
|
### User Operations
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| SignUp | Creates a self-service user for an app client. |
|
|
| ConfirmSignUp | Confirms a pending self-service signup. |
|
|
| GetUser | Returns attributes for the authenticated access-token user. |
|
|
| GetUserAttributeVerificationCode | Issues a verification code for the authenticated user's email or phone_number attribute. |
|
|
| VerifyUserAttribute | Verifies an email or phone_number attribute with its issued verification code. |
|
|
| UpdateUserAttributes | Updates attributes for the authenticated access-token user. |
|
|
| ChangePassword | Changes the authenticated user's password. |
|
|
| ForgotPassword | Starts the local forgot-password flow for a user. |
|
|
| ConfirmForgotPassword | Completes the forgot-password flow by setting a replacement password. |
|
|
|
|
### Authentication
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| InitiateAuth | Authenticates app-client users through supported user-password and SRP-style flows. |
|
|
| AdminInitiateAuth | Starts an admin authentication flow for a user pool user. |
|
|
| RespondToAuthChallenge | Responds to supported Cognito auth challenges. |
|
|
|
|
### User Listing
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| ListUsers | Lists users stored in a user pool. |
|
|
|
|
## Supported AuthFlow Values
|
|
|
|
`InitiateAuth` accepts `USER_PASSWORD_AUTH`, `USER_SRP_AUTH`, `CUSTOM_AUTH`, `USER_AUTH`,
|
|
`REFRESH_TOKEN_AUTH` and `REFRESH_TOKEN`. `AdminInitiateAuth` accepts `ADMIN_USER_PASSWORD_AUTH`,
|
|
`ADMIN_NO_SRP_AUTH`, `USER_SRP_AUTH`, `USER_PASSWORD_AUTH`, `CUSTOM_AUTH`, `USER_AUTH`,
|
|
`REFRESH_TOKEN_AUTH` and `REFRESH_TOKEN`.
|
|
|
|
`USER_AUTH` is the choice-based flow: with no `PREFERRED_CHALLENGE` it returns
|
|
`ChallengeName=SELECT_CHALLENGE` and an `AvailableChallenges` list drawn from what the user has
|
|
configured (`PASSWORD`, `PASSWORD_SRP`, `EMAIL_OTP`, `SMS_OTP`); with one, it goes straight to that
|
|
challenge. It requires the user pool's tier to be Essentials or higher. `WEB_AUTHN` and the
|
|
`ConfirmSignUp` session as a first-factor shortcut are not implemented yet.
|
|
|
|
Any other `AuthFlow` value is rejected with `InvalidParameterException` and no tokens are issued.
|
|
|
|
An app client only accepts the flows in its `ExplicitAuthFlows`: `ALLOW_USER_PASSWORD_AUTH`,
|
|
`ALLOW_USER_SRP_AUTH`, `ALLOW_CUSTOM_AUTH`, `ALLOW_USER_AUTH`, `ALLOW_ADMIN_USER_PASSWORD_AUTH` and
|
|
`ALLOW_REFRESH_TOKEN_AUTH`, or the legacy `USER_PASSWORD_AUTH`, `ADMIN_NO_SRP_AUTH` and
|
|
`CUSTOM_AUTH_FLOW_ONLY`. Any other flow fails with `InvalidParameterException`.
|
|
|
|
A client created without `ExplicitAuthFlows`, or with it cleared to an empty list, stores and describes an
|
|
empty list, matching AWS. It is enforced as if it had `ALLOW_REFRESH_TOKEN_AUTH`, `ALLOW_USER_SRP_AUTH` and
|
|
`ALLOW_CUSTOM_AUTH`, the default AWS documents for such a client: only the enforcement uses that default, not
|
|
the stored or returned value. A client that signs in with `USER_PASSWORD_AUTH`, `ADMIN_USER_PASSWORD_AUTH` or
|
|
`USER_AUTH` must list the matching `ALLOW_` value.
|
|
|
|
## User Attribute Update Verification
|
|
|
|
`CreateUserPool`, `UpdateUserPool`, and `DescribeUserPool` support
|
|
`UserAttributeUpdateSettings.AttributesRequireVerificationBeforeUpdate` for
|
|
`email` and `phone_number`.
|
|
|
|
For attributes listed in this setting, `UpdateUserAttributes` keeps the existing
|
|
verified value and sign-in alias active while the new value is pending. It sends
|
|
a verification code to the pending destination and returns the corresponding
|
|
entry in `CodeDeliveryDetailsList`. A successful `VerifyUserAttribute` promotes
|
|
the pending value, switches the alias, and sets the matching `*_verified`
|
|
attribute to `true`.
|
|
|
|
Without the setting, `UpdateUserAttributes` replaces the value immediately and
|
|
sets the matching `*_verified` attribute to `false` until verification succeeds.
|
|
A verification code is still sent to the replacement value, but Cognito no
|
|
longer retains or exposes the old value. For alias attributes, the old alias is
|
|
removed immediately and the replacement becomes usable for sign-in only after
|
|
successful verification. Incorrect or expired codes don't promote a pending
|
|
value or change its verified state.
|
|
|
|
### Groups
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateGroup | Creates a group in a user pool. |
|
|
| GetGroup | Returns a user-pool group. |
|
|
| UpdateGroup | Updates a user-pool group's stored settings. |
|
|
| ListGroups | Lists groups in a user pool. |
|
|
| ListUsersInGroup | Lists users assigned to a group. |
|
|
| DeleteGroup | Deletes a group from a user pool. |
|
|
| AdminAddUserToGroup | Adds a user to a group. |
|
|
| AdminRemoveUserFromGroup | Removes a user from a group. |
|
|
| AdminListGroupsForUser | Lists the groups assigned to a user. |
|
|
|
|
### Managed Login Branding
|
|
|
|
| Action | Description |
|
|
|--------|-------------|
|
|
| CreateManagedLoginBranding | Creates the branding for an app client. |
|
|
| DescribeManagedLoginBranding | Returns a branding by its id. |
|
|
| DescribeManagedLoginBrandingByClient | Returns the branding attached to an app client. |
|
|
| UpdateManagedLoginBranding | Updates a branding's settings, assets or provided-values flag. |
|
|
| DeleteManagedLoginBranding | Deletes a branding from its app client. |
|
|
|
|
`CreateManagedLoginBranding` must name either `UseCognitoProvidedValues` or `Settings`; a
|
|
request with neither is rejected. One branding per app client: a second
|
|
`CreateManagedLoginBranding` for the same client is rejected with
|
|
`ManagedLoginBrandingExistsException`. `ManagedLoginBrandingId` must be a
|
|
version 4 UUID, and a malformed one is rejected before the lookup, as AWS does.
|
|
`Assets` holds at most 40 entries on create and on update.
|
|
`Settings` is omitted from the response when the caller supplied none, while `Assets` is
|
|
always returned. Members an update omits are left unchanged.
|
|
|
|
The asset-count and branding-id checks run before the pool, client or branding is looked
|
|
up, so an oversized request naming something that does not exist reports the request
|
|
problem rather than `ResourceNotFoundException`, and an update violating both reports them
|
|
in one message with the asset list first.
|
|
|
|
Branding is presentation for the hosted UI, which Floci does not serve, so it is stored
|
|
and returned rather than rendered. Two divergences follow from that:
|
|
|
|
- **`Settings` is stored opaquely.** AWS validates it against a deep schema, rejecting
|
|
unknown properties with `Invalid settings provided. Validation errors: [{property:
|
|
$.components...., errorType: UnknownProperty}]`. That schema is not published, so Floci
|
|
accepts any object.
|
|
- **A wrongly typed `Settings` returns a client error.** AWS answers that particular input
|
|
with `InternalErrorException` and a 500; Floci returns
|
|
`SerializationException: Unexpected field type`, which is what AWS returns for a wrongly
|
|
typed `Assets`. Reproducing someone else's 500 seemed worse than being consistent.
|
|
- **`ReturnMergedResources` is not honoured.** Against AWS it merges Cognito's own default
|
|
settings and assets into the response: on a pool with 8 configured assets it returns 38.
|
|
Reproducing that needs Cognito's default corpus, so Floci returns the stored branding
|
|
either way.
|
|
|
|
## Well-Known And OAuth Endpoints
|
|
|
|
| Endpoint | Description |
|
|
|------------------------------------------------------|------------------------------------------------------------------|
|
|
| `GET /{userPoolId}/.well-known/openid-configuration` | OpenID discovery document |
|
|
| `GET /{userPoolId}/.well-known/jwks.json` | JSON Web Key Set for JWT validation |
|
|
| `GET /cognito-idp/oauth2/authorize` | OIDC authorization-code start endpoint |
|
|
| `GET /cognito-idp/oauth2/idpresponse` | OIDC provider callback endpoint |
|
|
| `POST /cognito-idp/oauth2/token` | OAuth authorization-code and client-credentials token endpoint |
|
|
|
|
The OAuth endpoints support browser-style OIDC authorization-code sign-in as well as the
|
|
emulator-friendly client-credentials flow:
|
|
|
|
- `GET /cognito-idp/oauth2/authorize` validates the app client and callback, then redirects
|
|
to the configured provider with an opaque state and nonce.
|
|
- `GET /cognito-idp/oauth2/idpresponse` consumes the provider state, exchanges the provider
|
|
code and redirects to the registered callback with a one-time Cognito authorization code.
|
|
- `POST /cognito-idp/oauth2/token` redeems that authorization code once, or issues a machine
|
|
token for `grant_type=client_credentials`.
|
|
|
|
`POST /cognito-idp/oauth2/token` is intentionally emulator-friendly rather than full Cognito parity:
|
|
|
|
- It requires an existing `client_id`.
|
|
- It accepts `client_id` and `client_secret` from the form body or Basic auth.
|
|
- Client-credentials requires a confidential app client created with `GenerateSecret=true`.
|
|
- Authorization-code redemption validates the client, callback URI and one-time code binding.
|
|
- It requires `AllowedOAuthFlowsUserPoolClient=true` and `AllowedOAuthFlows=["client_credentials"]`.
|
|
- It doesn't require a Cognito domain.
|
|
- Client-credentials returns only `access_token`, `token_type`, and `expires_in`; authorization-code
|
|
redemption returns the Cognito access, ID and refresh token set.
|
|
- It validates requested OAuth scopes against the app client's `AllowedOAuthScopes` and the pool's registered resource-server scopes.
|
|
- It advertises the prefixed token endpoint in `/{userPoolId}/.well-known/openid-configuration`, or
|
|
`https://<domain>/oauth2/token` when the pool has a custom domain (see Custom domains above).
|
|
|
|
## Sign-in Identifiers (`UsernameAttributes`)
|
|
|
|
Floci follows real Cognito semantics for pools created with `UsernameAttributes` (e.g.
|
|
`--username-attributes email`):
|
|
|
|
- `AdminCreateUser`/`SignUp` accept the email (or phone number) as the sign-in value, but the
|
|
**canonical `Username` is an auto-generated, immutable UUID equal to `sub`**. The supplied email is
|
|
stored as a mutable alias attribute.
|
|
- `ListUsers`, `AdminGetUser` and Lambda trigger `event.userName` all report the **UUID**, never the
|
|
email; the email lives in the `email` attribute and in `event.request.userAttributes.email`.
|
|
- Sign-in resolves by the **current** email alias **or** the UUID. `SECRET_HASH` is validated against
|
|
the exact `USERNAME` value sent: `Base64(HMAC-SHA256(USERNAME + clientId, clientSecret))`.
|
|
- In `CUSTOM_AUTH` / SRP flows, `ChallengeParameters.USERNAME` echoes the **UUID** (as real AWS does);
|
|
the `RespondToAuthChallenge` `SECRET_HASH` is validated against the `USERNAME` sent that round. That
|
|
`USERNAME` must still resolve to the session's user — the UUID or any of its current aliases — and a
|
|
value naming a different user is rejected with `NotAuthorizedException`.
|
|
- `AdminUpdateUserAttributes` can change the email; afterwards sign-in works with the new email and
|
|
fails with the old one, while `Username`/`sub` stay fixed.
|
|
- Duplicate email/phone on `AdminCreateUser`: `UsernameExistsException` when the incoming alias is
|
|
unverified, `AliasExistsException` when it is verified (`email_verified=true`); pass
|
|
`ForceAliasCreation=true` to migrate a verified alias off the previous owner. On
|
|
`AdminUpdateUserAttributes`, changing to an in-use alias throws `AliasExistsException`.
|
|
|
|
Pools **without** `UsernameAttributes` (classic pools, and pools using `AliasAttributes`) keep the
|
|
literal `Username` you supply, unchanged.
|
|
|
|
### Token claims
|
|
|
|
Floci mirrors AWS's access-token / ID-token split:
|
|
|
|
- **Access token:** `sub`, `username` (the UUID), `scope` (`aws.cognito.signin.user.admin` for API
|
|
sign-in), `client_id`, `cognito:groups`, `jti`/`origin_jti`. It does **not** carry `cognito:username`
|
|
or user attributes like `email`.
|
|
- **ID token:** `sub`, `cognito:username`, `aud`, and readable user attributes (`email`,
|
|
`email_verified`, `phone_number`, `custom:*`, ...). Attribute claims are filtered by the app client's
|
|
`ReadAttributes` (an unset/empty list means all attributes are readable).
|
|
|
|
Not-found errors (`ResourceNotFoundException`, `UserNotFoundException`) return HTTP `400`, matching the
|
|
Cognito JSON protocol.
|
|
|
|
## Configuration
|
|
|
|
| Variable | Default | Description |
|
|
|----------------------------------|---------|-------------------------------|
|
|
| `FLOCI_SERVICES_COGNITO_ENABLED` | `true` | Enable or disable the service |
|
|
|
|
## Examples
|
|
|
|
```bash
|
|
export AWS_ENDPOINT_URL=http://localhost:4566
|
|
|
|
# Create a user pool
|
|
POOL_ID=$(aws cognito-idp create-user-pool \
|
|
--pool-name MyApp \
|
|
--query UserPool.Id --output text \
|
|
--endpoint-url $AWS_ENDPOINT_URL)
|
|
|
|
# Create an app client
|
|
CLIENT_ID=$(aws cognito-idp create-user-pool-client \
|
|
--user-pool-id $POOL_ID \
|
|
--client-name my-client \
|
|
--generate-secret \
|
|
--allowed-o-auth-flows-user-pool-client \
|
|
--allowed-o-auth-flows client_credentials \
|
|
--allowed-o-auth-scopes notes/read notes/write \
|
|
--query UserPoolClient.ClientId --output text \
|
|
--endpoint-url $AWS_ENDPOINT_URL)
|
|
|
|
# Retrieve the generated client secret
|
|
CLIENT_SECRET=$(aws cognito-idp describe-user-pool-client \
|
|
--user-pool-id $POOL_ID \
|
|
--client-id $CLIENT_ID \
|
|
--query UserPoolClient.ClientSecret --output text \
|
|
--endpoint-url $AWS_ENDPOINT_URL)
|
|
|
|
# Register a resource server and scopes
|
|
aws cognito-idp create-resource-server \
|
|
--user-pool-id $POOL_ID \
|
|
--identifier notes \
|
|
--name "Notes API" \
|
|
--scopes ScopeName=read,ScopeDescription="Read notes" ScopeName=write,ScopeDescription="Write notes" \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# Create a user
|
|
aws cognito-idp admin-create-user \
|
|
--user-pool-id $POOL_ID \
|
|
--username alice@example.com \
|
|
--temporary-password Temp1234! \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# Set a permanent password
|
|
aws cognito-idp admin-set-user-password \
|
|
--user-pool-id $POOL_ID \
|
|
--username alice@example.com \
|
|
--password Perm1234! \
|
|
--permanent \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# Authenticate
|
|
aws cognito-idp initiate-auth \
|
|
--auth-flow USER_PASSWORD_AUTH \
|
|
--client-id $CLIENT_ID \
|
|
--auth-parameters USERNAME=alice@example.com,PASSWORD=Perm1234! \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# Create a group
|
|
aws cognito-idp create-group \
|
|
--user-pool-id $POOL_ID \
|
|
--group-name admin \
|
|
--description "Admin group" \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# Add user to group
|
|
aws cognito-idp admin-add-user-to-group \
|
|
--user-pool-id $POOL_ID \
|
|
--group-name admin \
|
|
--username alice@example.com \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# List groups for user
|
|
aws cognito-idp admin-list-groups-for-user \
|
|
--user-pool-id $POOL_ID \
|
|
--username alice@example.com \
|
|
--endpoint-url $AWS_ENDPOINT_URL
|
|
|
|
# Fetch the pool discovery document
|
|
curl -s "$AWS_ENDPOINT_URL/$POOL_ID/.well-known/openid-configuration"
|
|
|
|
# Get a machine access token from the OAuth endpoint
|
|
curl -s \
|
|
-X POST "$AWS_ENDPOINT_URL/cognito-idp/oauth2/token" \
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
-u "$CLIENT_ID:$CLIENT_SECRET" \
|
|
--data-urlencode "grant_type=client_credentials" \
|
|
--data-urlencode "scope=notes/read notes/write"
|
|
```
|
|
|
|
## JWT Validation
|
|
|
|
Tokens issued by Floci can be validated using the discovery and JWKS endpoints:
|
|
|
|
```
|
|
http://localhost:4566/$POOL_ID/.well-known/openid-configuration
|
|
```
|
|
|
|
```
|
|
http://localhost:4566/$POOL_ID/.well-known/jwks.json
|
|
```
|
|
|
|
Tokens include the `cognito:groups` claim as a JSON array when the authenticated user belongs to one or more groups.
|
|
|
|
Tokens issued by Cognito auth flows and the OAuth token endpoint use the emulator base URL plus the pool id:
|
|
|
|
```
|
|
http://localhost:4566/$POOL_ID
|
|
```
|
|
|
|
This keeps the issuer, discovery document, JWKS URL, and token endpoint internally consistent for local JWT validation while supporting LocalStack-style confidential clients and resource-server-backed scopes.
|