webiny-cognito-federation
GitHub配置 Webiny 项目的 Cognito 联邦身份认证,支持 Google、OIDC 等外部提供商登录。涵盖基础设施搭建、管理员登录界面定制及 API 身份映射同步。
Trigger Scenarios
Install
npx skills add webiny/webiny-js --skill webiny-cognito-federation -g -y
SKILL.md
Frontmatter
{
"name": "webiny-cognito-federation",
"description": "Configuring Cognito Federation for Webiny projects — federated sign-in via external identity providers (Google, Facebook, Apple, Amazon, OIDC\/Entra ID) while keeping Cognito as the user pool. Use this skill when the developer asks about Cognito federation, SSO with Cognito, adding Google\/Microsoft\/OIDC login to Cognito, federated identity providers, CognitoSignInConfig, CognitoIdpConfig, external users, signInWithRedirect, OAuth redirect URLs, hiding the password form, allowCredentialsLogin, or customizing the federated login screen."
}
Cognito Federation
TL;DR
Webiny supports federated sign-in through Cognito — users authenticate via external identity providers (Google, Entra ID, etc.) while Cognito remains the user pool. Configure it by adding a federation prop to <Cognito /> in webiny.config.tsx. This handles both infrastructure (Cognito User Pool Domain, IdP resources, OAuth client) and the admin login screen (provider buttons, OAuth for Amplify). Federated users are auto-detected and synced into Webiny. For advanced use cases, provide apiConfig (custom identity mapping) and/or adminConfig (custom login screen behavior).
Pattern / Core Concept
Cognito Federation has three layers:
-
Infrastructure — The
federationprop on<Cognito />, under the hood, creates the Cognito User Pool Domain, Identity Provider resources, and configures OAuth on the User Pool Client. -
Admin Login Screen — The federation config is passed as an
Admin.BuildParamto the admin app. ACognitoSignInConfigabstraction provides the login screen with provider buttons, OAuth settings for Amplify, and credentials visibility. By default, this is auto-generated from thefederationprop. For advanced customization (IP whitelists, async logic), provide anadminConfigextension. -
API Identity — Federated tokens are auto-detected via the
identitiesJWT claim and markedexternal: true. TheExternalIdpUserSyncHandlerauto-creates/updates users on login. For custom role/team mapping, provide anapiConfigextension implementingCognitoIdpConfig.
How Federated Login Works
- User clicks a provider button on the login screen
signInWithRedirect()redirects to Cognito Hosted UI- Cognito redirects to the external IdP (Google, Entra ID, etc.)
- After authentication, Cognito creates an
idTokenwith anidentitiesclaim - The admin app picks up the session via
fetchAuthSession() - The API detects
identitiesin the token, setsexternal: true ExternalIdpUserSyncHandlercreates/updates the Webiny user with roles/teams
Reference Tables
<Cognito /> Props
| Prop | Type | Description |
|---|---|---|
federation |
object | () => Promise<object> |
Federation config (see below) — sync or async |
mfa |
boolean |
Enable TOTP MFA for all users (default: false) |
apiConfig |
string |
Path to API identity mapping extension |
adminConfig |
string |
Path to Admin login customization extension |
federation Object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
domain |
string |
Yes | — | Cognito User Pool domain prefix |
callbackUrls |
string[] |
Yes | — | OAuth callback/redirect URLs |
logoutUrls |
string[] |
No | callbackUrls |
OAuth logout redirect URLs |
responseType |
"code" | "token" |
No | "code" |
OAuth response type |
allowCredentialsLogin |
boolean |
No | true |
Show email/password form |
identityProviders |
array |
Yes | — | List of federated IdPs |
identityProviders[] Items
| Field | Type | Required | Description |
|---|---|---|---|
type |
"google" | "facebook" | "amazon" | "apple" | "oidc" |
Yes | Provider type |
name |
string |
No | Custom provider name (required for OIDC) |
label |
string |
Yes | Button text on the login screen |
providerDetails |
object |
Yes | AWS Cognito provider details (client_id, client_secret, etc.) |
attributeMapping |
object |
No | Custom attribute mapping (overrides defaults) |
CognitoSignInConfig.Interface (Admin Customization)
| Method | Signature | Description |
|---|---|---|
getConfig() |
() => Promise<Config> |
Returns federation config for the login screen |
CognitoSignInConfig.Config (Return Type)
| Field | Type | Required | Description |
|---|---|---|---|
oauth |
{ scopes, redirectSignIn, redirectSignOut, responseType } |
Yes | Amplify OAuth config |
allowCredentialsLogin |
boolean |
Yes | Show email/password form |
providers |
FederatedProvider[] |
Yes | Provider buttons |
title |
string |
No | Login screen title (default: "Sign in") |
description |
string |
No | Login screen description |
FederatedProvider (Union Type)
type FederatedProvider =
| { name: string; label: string } // Auto-rendered button
| { name: string; component: React.FC<{ signIn: () => void }> }; // Custom button
CognitoIdpConfig.Interface (API Identity Mapping)
| Method | Signature | Required | Description |
|---|---|---|---|
getIdentity |
(token: JwtPayload) => CognitoIdentity | Promise<CognitoIdentity> |
Yes | Maps JWT claims to Webiny identity |
verifyTokenClaims |
(token: JwtPayload) => void | Promise<void> |
No | Custom claim verification |
Identity Return Type
Default identity fields (id, displayName, profile) are auto-populated from standard Cognito claims (custom:id, given_name, family_name, email). The custom getIdentity only needs to return fields it wants to override — typically roles and teams.
| Field | Type | Description |
|---|---|---|
id |
string |
User ID (default: custom:id or sub) |
displayName |
string |
Display name (default: from name claims) |
roles |
string[] |
Webiny roles by slug |
teams |
string[] |
Webiny teams by slug |
profile |
{ email, firstName, lastName } |
User profile (defaults from claims) |
Full Examples
Example 1: Simple Federation (No Extension Files)
// webiny.config.tsx
import { Cognito } from "@webiny/cognito";
<Cognito
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001", "https://admin.example.com"],
responseType: "code",
identityProviders: [
{
type: "google",
label: "Sign in with Google",
providerDetails: {
authorize_scopes: "email profile openid",
client_id: String(process.env.GOOGLE_CLIENT_ID),
client_secret: String(process.env.GOOGLE_CLIENT_SECRET)
}
}
]
}}
/>;
This alone creates the Cognito IdP, configures OAuth, shows a "Sign in with Google" button, and auto-syncs federated users.
Example 2: OIDC Provider (Entra ID / Custom)
<Cognito
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001"],
responseType: "code",
allowCredentialsLogin: false,
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)
}
}
]
}}
/>
Example 3: Async Federation Config
When provider credentials need to be fetched asynchronously (e.g., from a secrets manager, vault, or remote API), pass federation as an async function instead of a plain object. The config rendering pipeline will wait for the promise to resolve before continuing.
// extensions/idp/entraid/Extension.tsx
import React from "react";
import { Cognito } from "@webiny/cognito";
async function getCredentials() {
return {
client_id: process.env.ENTRA_CLIENT_ID,
client_secret: process.env.ENTRA_CLIENT_SECRET,
oidc_issuer: process.env.ENTRA_OIDC_ISSUER
};
}
export const CognitoFederation = () => {
return (
<Cognito
mfa={true}
apiConfig={"@/extensions/idp/entraid/EntraIdApiConfig.ts"}
federation={async () => {
const credentials = await getCredentials();
return {
domain: "myproj-webiny-with-entraid",
callbackUrls: ["https://webiny-6.4.x.localhost"],
responseType: "code",
allowCredentialsLogin: true,
identityProviders: [
{
name: "EntraID",
type: "oidc",
label: "Sign in with Microsoft",
providerDetails: {
attributes_request_method: "POST",
authorize_scopes: "email profile openid",
...credentials
},
attributeMapping: {
"custom:id": "sub",
username: "sub",
email: "email",
given_name: "given_name",
family_name: "family_name",
preferred_username: "email"
}
}
]
};
}}
/>
);
};
Under the hood, the <Cognito> component uses <Await fn={...}> from @webiny/react-properties to resolve the async function. The AsyncProperties wrapper in the config rendering worker gates onChange until all <Await> promises settle, so the CLI won't exit prematurely.
Example 4: Multiple Providers
<Cognito
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001"],
responseType: "code",
identityProviders: [
{
type: "google",
label: "Sign in with Google",
providerDetails: {
authorize_scopes: "email profile openid",
client_id: String(process.env.GOOGLE_CLIENT_ID),
client_secret: String(process.env.GOOGLE_CLIENT_SECRET)
}
},
{
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)
}
}
]
}}
/>
Example 5: Custom Identity Mapping (apiConfig)
Map Cognito groups to Webiny roles/teams:
// webiny.config.tsx
<Cognito federation={{/* ... */}} apiConfig={"/extensions/cognito/api.ts"} />
// extensions/cognito/api.ts
import { CognitoIdpConfig } from "@webiny/cognito/api";
class MyConfig implements CognitoIdpConfig.Interface {
getIdentity(token: CognitoIdpConfig.JwtPayload) {
const cognitoGroups: string[] = (token["cognito:groups"] as string[]) || [];
return {
roles: cognitoGroups.includes("admins") ? ["full-access"] : ["content-editor"],
teams: cognitoGroups.filter(g => g.startsWith("team-"))
};
}
}
export default CognitoIdpConfig.createImplementation({
implementation: MyConfig,
dependencies: []
});
Example 6: Custom Admin Login Screen (adminConfig)
IP-based credentials whitelist
// webiny.config.tsx
<Cognito federation={{/* ... */}} adminConfig={"/extensions/cognito/admin.tsx"} />
// extensions/cognito/admin.tsx
import { CognitoSignInConfig } from "@webiny/cognito/admin";
const ALLOWED_IPS = ["1.2.3.4", "5.6.7.8"];
async function fetchUserIP(): Promise<string> {
const response = await fetch("https://api64.ipify.org?format=json");
const data = await response.json();
return data.ip;
}
class MyFederationConfig implements CognitoSignInConfig.Interface {
async getConfig() {
let allowCredentials = false;
if (process.env.REACT_APP_STAGE !== "prod") {
const ip = await fetchUserIP();
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" }],
title: "Welcome"
};
}
}
export default CognitoSignInConfig.createImplementation({
implementation: MyFederationConfig,
dependencies: []
});
Custom button component
// extensions/cognito/admin.tsx
import { CognitoSignInConfig } from "@webiny/cognito/admin";
import { GoogleLoginButton } from "react-social-login-buttons";
class MyFederationConfig implements CognitoSignInConfig.Interface {
async getConfig() {
return {
oauth: {
scopes: ["profile", "email", "openid"],
redirectSignIn: [window.location.origin],
redirectSignOut: [window.location.origin],
responseType: "code" as const
},
allowCredentialsLogin: true,
providers: [
{
name: "google",
component: ({ signIn }) => <GoogleLoginButton onClick={signIn} />
}
]
};
}
}
export default CognitoSignInConfig.createImplementation({
implementation: MyFederationConfig,
dependencies: []
});
Custom title and description
class MyFederationConfig implements CognitoSignInConfig.Interface {
async getConfig() {
return {
oauth: {/* ... */},
allowCredentialsLogin: false,
providers: [{ name: "EntraID", label: "Sign In" }],
title: "Company Portal",
description: "Use your corporate credentials to sign in."
};
}
}
Example 7: Custom Attribute Mapping
Override the default OIDC attribute mapping when your IdP uses non-standard claim names.
The custom:id mapping is important — Webiny uses it as the primary user identifier. It's mapped to the IdP's sub claim by default. Always include it in custom mappings unless the IdP's sub value exceeds 36 characters on an existing Cognito pool (deployed prior to Webiny 6.4.4). New pools support up to 256 characters.
<Cognito
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001"],
identityProviders: [
{
name: "MyIDP",
type: "oidc",
label: "Sign in with MyIDP",
providerDetails: {
authorize_scopes: "email profile openid",
client_id: "...",
client_secret: "...",
oidc_issuer: "..."
},
attributeMapping: {
"custom:id": "sub",
username: "sub",
email: "email",
given_name: "first_name",
family_name: "last_name"
}
}
]
}}
/>
MFA (Multi-Factor Authentication)
Enable TOTP-based MFA for all admin users with mfa={true}:
<Cognito mfa={true} />
Or combine with federation:
<Cognito
mfa={true}
federation={{
domain: "my-app",
callbackUrls: ["http://localhost:3001"],
identityProviders: [
{
name: "EntraID",
type: "oidc",
label: "Sign in with Microsoft",
providerDetails: {/* ... */}
}
]
}}
/>
When MFA is enabled:
- The Cognito User Pool requires TOTP for all users (
mfaConfiguration: "ON") - On first login, users see a TOTP setup screen with a QR code to scan with their authenticator app (Google Authenticator, Authy, etc.)
- On subsequent logins, users enter a 6-digit code from their authenticator app
- MFA applies to password-based logins only — federated IdP logins are handled by the external provider
Quick Reference
Imports
// Extension component
import { Cognito } from "@webiny/cognito";
// API identity mapping
import { CognitoIdpConfig } from "@webiny/cognito/api";
// Admin login customization
import { CognitoSignInConfig } from "@webiny/cognito/admin";
Key Interfaces
| Interface | Package | Purpose |
|---|---|---|
CognitoIdpConfig.Interface |
@webiny/cognito/api |
API-side JWT-to-identity mapping |
CognitoIdpConfig.JwtPayload |
@webiny/cognito/api |
JWT token payload type |
CognitoSignInConfig.Interface |
@webiny/cognito/admin |
Admin login screen customization |
CognitoSignInConfig.FederatedProvider |
@webiny/cognito/admin |
Provider button type (label or component) |
File Structure (Advanced)
extensions/cognito/
├── api.ts # API config (identity mapping) — optional
└── admin.tsx # Admin config (login customization) — optional
Deploy
yarn webiny deploy # Deploy all (Core + API + Admin)
Core must be deployed first (creates IdP resources), then API + Admin.
Related Skills
- webiny-configure-entraid — Specific guide for Microsoft Entra ID federation
- webiny-configure-okta — Alternative: Okta replaces Cognito entirely
- webiny-configure-auth0 — Alternative: Auth0 replaces Cognito entirely
- webiny-dependency-injection — The DI pattern used by
createImplementation()
Version History
- 80eb1c5 Current 2026-08-20 10:07


