Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/developer-docs/6.x/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export const Navigation = ({ children }: { children: React.ReactNode }) => {
<Page link={"security/roles"} />
<Page link={"security/teams"} />
<Page link={"security/universal-api-keys"} />
<Page link={"security/cognito-federation"} />
</Group>
<Separator title={"Operations"} />
<Group title={"CLI"} icon={"/docs/menu-icons/cli.svg"} link={"cli/deploy"}>
Expand Down
45 changes: 45 additions & 0 deletions docs/developer-docs/6.x/security/cognito-federation.ai.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
AI Context: Cognito Federation (cognito-federation.mdx)

Source of Information:
1. packages/cognito/src/Cognito.tsx — defineExtension with federation prop, Pulumi hook, Admin.BuildParam
2. packages/cognito/src/admin/presentation/Cognito/CognitoSignInConfig.ts — ICognitoSignInConfig interface, FederatedProvider union type
3. packages/cognito/src/admin/presentation/Cognito/CognitoPresenter.ts — resolves CognitoSignInConfig, configures Amplify OAuth, populates vm.signIn
4. packages/cognito/src/admin/DefaultCognitoSignInConfig.ts — auto-generated config from BuildParam
5. packages/cognito/src/api/features/CognitoIdp/CognitoIdentityProvider.ts — detects identities claim, sets external: true, merges custom getIdentity
6. packages/cognito/src/api/features/CognitoIdp/abstractions.ts — CognitoIdpConfig interface
7. packages/api-core/src/features/users/ExternalIdpUserSync/ExternalIdpUserSyncHandler.ts — auto-creates/updates external users on AfterLogin
8. packages/cognito/src/infra/CognitoFederationPulumi.ts — CorePulumi hook calling configureAdminCognitoFederation
9. packages/project-aws/src/pulumi/apps/core/cognitoIdentityProviders/configure.ts — configureAdminCognitoFederation, creates domain/IdP/OAuth client
10. packages/cognito/src/admin/presentation/Cognito/components/FederatedLogin.tsx — renders provider buttons, calls signInWithRedirect
11. packages/cognito/src/admin/presentation/Cognito/components/SignIn.tsx — conditionally renders credentials form, FederatedLogin, Divider
12. skills/user-skills/cognito-federation/SKILL.md — full reference skill
13. skills/user-skills/configure-entraid/SKILL.md — Entra ID specific skill

Key Documentation Decisions:
1. No step-by-step setup guide — AI assistants with Webiny MCP can generate the config from a prompt; the docs focus on concepts and capabilities
2. "Setting It Up with AI" section shows an example prompt for MCP-equipped AI assistants
3. Custom identity mapping only shows overriding roles/teams — defaults for id, displayName, profile are auto-populated from standard Cognito claims
4. adminConfig async example demonstrates IP whitelisting — the most common advanced use case
5. Deploy order section is essential because core must be deployed first to create the Cognito domain, which must then be configured in the external IdP before admin can work

Understanding:
The federation prop on <Cognito /> handles three concerns:
1. Infrastructure (Pulumi) — configureAdminCognitoFederation() creates User Pool Domain, IdentityProvider resources, and configures OAuth on the UserPoolClient
2. Admin login screen — federation config is passed as Admin.BuildParam; DefaultCognitoSignInConfig reads it and implements CognitoSignInConfig.getConfig(); CognitoPresenter resolves it, configures Amplify.configure() with loginWith.oauth, and populates vm.signIn with title/description/allowCredentialsLogin/federatedProviders
3. API identity — CognitoIdentityProvider.getIdentity() builds default identity from token claims, then merges custom CognitoIdpConfig result on top; detects federated users via Boolean(token.identities) and sets external: true; ExternalIdpUserSyncHandler fires on AfterLogin and creates/updates users when external is true

FederatedProvider is a union: { name, label } renders a default Button; { name, component } renders a custom React component receiving { signIn } callback.

The adminConfig extension replaces the auto-generated DefaultCognitoSignInConfig with a custom implementation. Because getConfig() is async, runtime checks (IP whitelisting, environment detection) work naturally.

Related Documents:
- docs/developer-docs/6.x/security/roles.mdx — RoleFactory, roles referenced by slug in identity mapping
- docs/developer-docs/6.x/security/teams.mdx — TeamFactory, teams referenced by slug in identity mapping
- docs/developer-docs/6.x/core-concepts/di.mdx — DI pattern used by CognitoIdpConfig and CognitoSignInConfig

Key Code Locations:
- packages/cognito/src/Cognito.tsx — extension definition with federation schema
- packages/cognito/src/admin/presentation/Cognito/CognitoSignInConfig.ts — ICognitoSignInConfig, FederatedProvider
- packages/cognito/src/admin/presentation/Cognito/CognitoPresenter.ts — presenter integration
- packages/cognito/src/api/features/CognitoIdp/CognitoIdentityProvider.ts — identity resolution
- packages/cognito/src/api/features/CognitoIdp/abstractions.ts — CognitoIdpConfig
255 changes: 255 additions & 0 deletions docs/developer-docs/6.x/security/cognito-federation.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
---
id: a7k2m9x1
title: Cognito Federation
description: Add federated sign-in (Google, Microsoft Entra ID, OIDC) to the Admin app while keeping Cognito as your user pool.
---

import { Alert } from "@/components/Alert";

<Alert type="success" title="WHAT YOU'LL LEARN">

- what Cognito Federation is and when to use it
- how to add external identity providers to the login screen
- how federated users are synced into Webiny
- how to customize identity mapping and login screen behavior

</Alert>

## Overview

By default, Webiny uses a Cognito User Pool where admin users are created manually through the Admin app. Cognito Federation lets you connect external identity providers — Google, Microsoft Entra ID, Facebook, Apple, or any OIDC-compatible provider — so users can sign in with their existing corporate or social credentials.

Unlike switching to Okta or Auth0 (which replace Cognito entirely), federation keeps Cognito as your user pool. The external provider handles authentication; Cognito issues the tokens; Webiny manages the users.

### What Happens When a Federated User Signs In

1. The user clicks a provider button (e.g., "Sign in with Microsoft") on the login screen.
2. Cognito redirects to the external identity provider.
3. After authentication, Cognito creates a session with an `idToken` that includes an `identities` claim.
4. Webiny detects the `identities` claim and marks the user as **external**.
5. On first login, the user is automatically created in Webiny with the roles and teams derived from token claims.
6. On subsequent logins, the user profile is updated if claims have changed.

External users appear in the Admin app's user management with a read-only badge — they cannot be edited or deleted through the UI since they are managed by the external identity provider.

## Configuring Federation

Add a `federation` prop to the `<Cognito />` extension in your `webiny.config.tsx`. This single declaration handles:

- **AWS infrastructure** — creates the Cognito User Pool Domain, Identity Provider resources, and configures OAuth on the User Pool Client
- **Admin login screen** — shows provider buttons and configures Amplify for the OAuth redirect flow

```tsx webiny.config.tsx
import { Cognito } from "@webiny/cognito";

<Cognito
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001", "https://admin.example.com"],
responseType: "code",
identityProviders: [
{
name: "EntraID",
type: "oidc",
label: "Sign in with Microsoft",
providerDetails: {
attributes_request_method: "POST",
authorize_scopes: "email profile openid",
client_id: String(process.env.ENTRA_CLIENT_ID),
client_secret: String(process.env.ENTRA_CLIENT_SECRET),
oidc_issuer: String(process.env.ENTRA_ISSUER),
}
}
]
}}
/>
```

### Federation Config Reference

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `domain` | `string` | Yes | — | Cognito User Pool domain prefix |
| `callbackUrls` | `string[]` | Yes | — | OAuth callback URLs (localhost for dev, real domain for prod) |
| `logoutUrls` | `string[]` | No | same as `callbackUrls` | OAuth logout redirect URLs |
| `responseType` | `"code"` or `"token"` | No | `"code"` | OAuth response type |
| `allowCredentialsLogin` | `boolean` | No | `true` | Whether to show the email/password form alongside provider buttons |
| `identityProviders` | array | Yes | — | List of external identity providers |

### Identity Provider Config

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | `"google"`, `"facebook"`, `"amazon"`, `"apple"`, or `"oidc"` | Yes | Provider type |
| `name` | `string` | For OIDC | Provider name in Cognito (e.g., `"EntraID"`) |
| `label` | `string` | Yes | Button text on the login screen |
| `providerDetails` | `object` | Yes | AWS Cognito provider details — varies by type |
| `attributeMapping` | `object` | No | Override default claim-to-attribute mapping |

<Alert type="info">

For OIDC providers, `providerDetails` must include `client_id`, `client_secret`, and `oidc_issuer`. For social providers (Google, Facebook, etc.), see the [AWS documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-social-idp.html) for the required fields.

</Alert>

## SSO-Only Mode

To hide the email/password form and show only the federated provider buttons, set `allowCredentialsLogin: false`:

```tsx
<Cognito
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001"],
allowCredentialsLogin: false,
identityProviders: [
{
name: "EntraID",
type: "oidc",
label: "Sign in with Microsoft",
providerDetails: { /* ... */ }
}
]
}}
/>
```

The login screen will display a description telling users they'll be redirected to an external service.

## Custom Identity Mapping

By default, federated users are created in Webiny with the `full-access` role. To control how token claims map to Webiny roles and teams, provide an `apiConfig` extension:

```tsx webiny.config.tsx
<Cognito
federation={{ /* ... */ }}
apiConfig={"/extensions/cognito/api.ts"}
/>
```

```typescript extensions/cognito/api.ts
import { CognitoIdpConfig } from "@webiny/cognito";

class MyConfig implements CognitoIdpConfig.Interface {
getIdentity(token: CognitoIdpConfig.JwtPayload) {
const groups: string[] = (token["cognito:groups"] as string[]) || [];

return {
roles: groups.includes("admins") ? ["full-access"] : ["content-editor"],
teams: groups.filter(g => g.startsWith("team-")),
};
}
}

export default CognitoIdpConfig.createImplementation({
implementation: MyConfig,
dependencies: []
});
```

<Alert type="info">

You only need to return the fields you want to override. Default values for `id`, `displayName`, and `profile` are automatically derived from standard Cognito token claims (`custom:id`, `given_name`, `family_name`, `email`).

</Alert>

## Custom Login Screen Behavior

For advanced login screen customization — such as IP-based credential whitelisting or custom provider buttons — provide an `adminConfig` extension that implements `CognitoSignInConfig`:

```tsx webiny.config.tsx
<Cognito
federation={{ /* ... */ }}
adminConfig={"/extensions/cognito/admin.tsx"}
/>
```

```tsx extensions/cognito/admin.tsx
import { CognitoSignInConfig } from "@webiny/cognito/admin";

class MySignInConfig implements CognitoSignInConfig.Interface {
async getConfig() {
return {
oauth: {
scopes: ["profile", "email", "openid"],
redirectSignIn: [window.location.origin],
redirectSignOut: [window.location.origin],
responseType: "code" as const,
},
allowCredentialsLogin: false,
providers: [
{ name: "EntraID", label: "Sign in with Microsoft" }
],
title: "Welcome",
description: "Use your corporate credentials to sign in.",
};
}
}

export default CognitoSignInConfig.createImplementation({
implementation: MySignInConfig,
dependencies: []
});
```

Because `getConfig()` is async, you can perform runtime checks before returning the config:

```tsx extensions/cognito/admin.tsx
import { CognitoSignInConfig } from "@webiny/cognito/admin";

const ALLOWED_IPS = ["1.2.3.4", "5.6.7.8"];

class MySignInConfig implements CognitoSignInConfig.Interface {
async getConfig() {
let allowCredentials = false;
if (process.env.REACT_APP_STAGE !== "prod") {
const res = await fetch("https://api64.ipify.org?format=json");
const { ip } = await res.json();
allowCredentials = ALLOWED_IPS.includes(ip);
}

return {
oauth: {
scopes: ["profile", "email", "openid"],
redirectSignIn: [window.location.origin],
redirectSignOut: [window.location.origin],
responseType: "code" as const,
},
allowCredentialsLogin: allowCredentials,
providers: [
{ name: "EntraID", label: "Sign in with Microsoft" }
],
};
}
}

export default CognitoSignInConfig.createImplementation({
implementation: MySignInConfig,
dependencies: []
});
```

## Setting It Up with AI

If you have the Webiny MCP server connected, you can configure federation with a single prompt:

> Set up Cognito Federation with Microsoft Entra ID. My tenant ID is `0ae3d912-...`, client ID is `f62ee823-...`, and client secret is `~Hp8Q~...`. Use SSO-only mode — no password login. Map all federated users to the `full-access` role.

The AI assistant has access to the `webiny-cognito-federation` and `webiny-configure-entraid` skills and will generate the complete configuration.

## Deploy Order

1. **Deploy Core** — creates the Cognito User Pool Domain and Identity Provider resources
```bash
yarn webiny deploy core --env=dev
```

2. **Configure the external IdP** — update the redirect URI in your identity provider's settings to:
`https://{cognitoUserPoolDomain}/oauth2/idpresponse`
(get the domain from `yarn webiny output core --env=dev`)

3. **Deploy API + Admin**
```bash
yarn webiny deploy api --env=dev
yarn webiny deploy admin --env=dev
```
8 changes: 8 additions & 0 deletions docs/release-notes/6.4.4/changelog.ai.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
AI Context: 6.4.4 Changelog (changelog.mdx)

This file tracks manual edits made after the generation script ran.
The script reads the "Skipped PRs" section to avoid re-adding removed entries.

## Skipped PRs

## Manual Rewrites
70 changes: 70 additions & 0 deletions docs/release-notes/6.4.4/changelog.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
id: k5mqyohu
title: Webiny 6.4.4 Changelog
description: See what's new in Webiny version 6.4.4
---

import { GithubRelease } from "@/components/GithubRelease";
import { Alert } from "@/components/Alert";

<GithubRelease version={"6.4.4"} />

## Infrastructure

### Custom Production Environments Are Now Recognized During Deployment ([#5371](https://github.com/webiny/webiny-js/pull/5371))

Marking an environment as a production environment via the `Infra.ProductionEnvironments` setting in `webiny.config.tsx` previously had no effect — only the built-in `prod` and `production` names were treated as production, so custom environments (like `stage`) never received production-grade infrastructure such as a VPC. Configured production environments are now correctly recognized and deployed with the appropriate production setup.

<Alert type="warning">

If an environment was already deployed before being marked as production, the next deploy will create the VPC, move existing Lambdas into it, add VPC endpoints, and enable resource protection. This is a disruptive infrastructure migration that may replace resources and cause downtime. Review `pulumi preview` carefully and deploy during a maintenance window.

</Alert>

## Development

### Faster Stack Output Reads via Local Caching ([#5375](https://github.com/webiny/webiny-js/pull/5375))

Every stack output lookup previously ran a Pulumi command, which made repeated reads slow—especially during deploys, watch mode, and output lookups that query the same stack multiple times. Stack outputs are now cached locally (under `.webiny/caches/stack-output`) and reused on subsequent reads. The cache is automatically cleared when an app is destroyed, so results always stay accurate.

## Admin

### Cognito Federation and Multi-Factor Authentication Support ([#5376](https://github.com/webiny/webiny-js/pull/5376))

Webiny now supports federated sign-in through Amazon Cognito, allowing users to authenticate via external identity providers such as Google, Facebook, Apple, Amazon, and any OIDC-compliant provider (e.g., Microsoft Entra ID). This eliminates the need for users to manage separate Webiny credentials when your organization already has an identity provider in place.

To enable federation, use the `federation` prop on the `<Cognito />` extension:

```typescript
import { Cognito } from "webiny/api-security-cognito";

export default createExtension({
type: "api",
name: "api.security.cognito",
create() {
return [
new Cognito({
federation: {
providers: [
{
type: "oidc",
name: "EntraID",
label: "Sign in with Microsoft"
}
]
}
})
];
}
});
```

Federated users are automatically detected via the `identities` claim in the JWT token and flagged as external, triggering the `ExternalIdpUserSyncHandler` for identity mapping and provisioning.

The login screen can be customized through the `adminConfig` extension point to control which providers appear, whether username/password credentials are shown, and to set custom titles or descriptions.

<Alert type="info">

For new deployments, the `custom:id` attribute maximum length has been increased to 256 characters to accommodate longer OIDC `sub` values from some identity providers. Existing deployments retain the 36-character limit.

</Alert>
Loading