All skills
aws avatar

/aws-amplify

@7898a91

Build and deploy full-stack web and mobile apps with AWS Amplify Gen2 (TypeScript code-first). Covers auth (Cognito), data (AppSync/DynamoDB), storage (S3), functions, APIs, and AI (Amplify AI Kit with Bedrock). Supports React, Next.js, Vue, Angular, React Native, Flutter, Swift, and Android. Always use this skill for Amplify Gen2 topics — even for questions you think you know — it contains validated, version-specific patterns that prevent common mistakes. TRIGGER when: user mentions Amplify Gen2; project has amplify/ directory or amplify_outputs; code imports @aws-amplify packages; user asks about defineBackend, defineAuth, defineData, defineStorage, defineFunction, or npx ampx. SKIP: Amplify Gen1 (amplify CLI v6), standalone SAM/CDK without Amplify (use aws-serverless), direct Bedrock without Amplify AI Kit (use bedrock).

Use this Skill: https://skilld.dev/gh/aws/agent-toolkit-for-aws/aws-amplify

This session only. Nothing lands on disk.

referencesauth-backend.md

≈2.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Auth — Backend

Prerequisites: Backend defined in amplify/backend.ts with defineBackend({ auth, data }).

Basic Auth Setup

Define authentication in amplify/auth/resource.ts:

import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
    // phone: true, // SMS-based login
  },
  userAttributes: {
    preferredUsername: { required: false },
  },
});

Import into amplify/backend.ts:

import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
defineBackend({ auth });

MFA Configuration

export const auth = defineAuth({
  loginWith: { email: true },
  multifactor: {
    mode: 'REQUIRED', // or 'OPTIONAL'
    totp: true,
    sms: true,
    email: true,
  },
});

Set mode: 'REQUIRED' to enforce MFA for all users. 'OPTIONAL' lets users enable it themselves.

Frontend impact: When MFA is enabled, the Authenticator component handles all MFA steps automatically. For custom UI, see auth-web.md for signInStep handling.

Passwordless Authentication

Passwordless login methods can coexist with traditional password-based auth.

Email OTP:

export const auth = defineAuth({
  loginWith: {
    email: {
      otpLogin: true,
    },
  },
});

SMS OTP:

export const auth = defineAuth({
  loginWith: {
    phone: {
      otpLogin: true,
    },
  },
});

WebAuthn / Passkeys:

export const auth = defineAuth({
  loginWith: {
    webAuthn: true,
  },
});

These passwordless methods can be combined with each other and with password-based login in the same defineAuth configuration.

Social Login

Use secret() for OAuth client secrets — hardcoding credentials exposes them in source control.

import { defineAuth, secret } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
    externalProviders: {
      google: {
        clientId: secret('GOOGLE_CLIENT_ID'),
        clientSecret: secret('GOOGLE_CLIENT_SECRET'),
        scopes: ['email', 'profile', 'openid'],
        attributeMapping: {
          email: 'email', // values are strings, NOT objects
          fullname: 'name',
        },
      },
      facebook: { clientId: secret('FB_CLIENT_ID'), clientSecret: secret('FB_CLIENT_SECRET') },
      signInWithApple: {
        clientId: secret('APPLE_CLIENT_ID'),
        teamId: secret('APPLE_TEAM_ID'),
        keyId: secret('APPLE_KEY_ID'),
        privateKey: secret('APPLE_PRIVATE_KEY'),
      },
      loginWithAmazon: { clientId: secret('AMAZON_CLIENT_ID'), clientSecret: secret('AMAZON_CLIENT_SECRET') },
      callbackUrls: ['http://localhost:3000/', 'https://myapp.com/'],
      logoutUrls: ['http://localhost:3000/', 'https://myapp.com/'],
    },
  },
});

Set secrets via CLI: echo -n "<value>" | npx ampx sandbox secret set MY_OAUTH_CLIENT_ID. (The documented approach uses an interactive prompt; piping with echo -n is a practical alternative for scripts.) For provider-specific OAuth setup guides, consult AWS documentation via available tools; when unavailable, use web search or AWS CLI.

SAML / OIDC (Enterprise)

OIDC providers are configured inside loginWith.externalProviders:

import { defineAuth, secret } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
    externalProviders: {
      oidc: [{
        name: 'MyOIDC',
        clientId: secret('OIDC_CLIENT_ID'),
        clientSecret: secret('OIDC_CLIENT_SECRET'),
        issuerUrl: 'https://idp.example.com',
        attributeMapping: { email: 'email' },
      }],
      callbackUrls: ['http://localhost:3000/'],
      logoutUrls: ['http://localhost:3000/'],
    },
  },
});

SAML is NOT supported in defineAuth — the ExternalProviderSpecificFactoryProps type has no saml property. The lower-level auth-construct package supports SAML, but it was never wired up to the high-level API. Use CDK escape hatches via backend.auth.resources to configure SAML providers:

// In backend.ts — SAML requires CDK-level configuration
const { cfnUserPool } = backend.auth.resources.cfnResources;
// Configure SAML identity provider via CfnUserPoolIdentityProvider

Consult AWS documentation for CfnUserPoolIdentityProvider SAML configuration properties.

Cognito Triggers

import { defineAuth } from '@aws-amplify/backend';
import { preSignUp } from './pre-sign-up/resource';
import { postConfirmation } from './post-confirmation/resource';

export const auth = defineAuth({
  loginWith: { email: true },
  triggers: {
    preSignUp,
    postConfirmation,
    // Also: preAuthentication, postAuthentication,
    // createAuthChallenge, defineAuthChallenge, verifyAuthChallengeResponse,
    // preTokenGeneration, customMessage, userMigration
  },
});

Define each trigger with defineFunction:

// amplify/auth/pre-sign-up/resource.ts
import { defineFunction } from '@aws-amplify/backend';
export const preSignUp = defineFunction({ name: 'pre-sign-up' });

Tip: Auth trigger handlers need @types/aws-lambda for TypeScript types.

Trigger Lambda + Data Table Access

If a trigger Lambda (e.g., postConfirmation) needs to write to a defineData table, this can create a circular dependency. Workarounds:

  1. Access via backend.auth.resources (avoids cycle when trigger is in auth stack):
// backend.ts
const postConfirmFn = backend.auth.resources.userPool.triggers?.postConfirmation;
const table = backend.data.resources.tables['UserProfile'];
table.grantWriteData(postConfirmFn);
postConfirmFn.addEnvironment('TABLE_NAME', table.tableName);
  1. Separate DynamoDB table — create via CDK (not defineData) to avoid stack coupling.

Guest (Unauthenticated) Access

Guest access is enabled by default in Amplify Gen2 — the Cognito Identity Pool is created with allowUnauthenticatedIdentities: true automatically.

To use guest access in your data models, set defaultAuthorizationMode to 'iam' and add allow.guest() authorization rules:

const schema = a.schema({
  Todo: a.model({
    content: a.string(),
  }).authorization(allow => [
    allow.guest().to(['read']),   // unauthenticated users can read
    allow.owner(),                // owners can CRUD
  ]),
});

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: 'iam',   // required for guest access
    apiKeyAuthorizationMode: { expiresInDays: 7 }, // optional alternative
  },
});

Security: Guest access grants unauthenticated users IAM-authorized access. For production, explicitly evaluate whether guest access is needed and prefer allow.authenticated() as the default. If guest access is required, scope it to read-only on non-sensitive models only.

To disable guest access, use a CDK override in backend.ts:

const { cfnIdentityPool } = backend.auth.resources.cfnResources;
cfnIdentityPool.allowUnauthenticatedIdentities = false;

Pitfalls

  • Trigger not registered (silent no-op): Defining a trigger function with defineFunction but NOT adding it to triggers: {} in defineAuth causes a silent no-op — the function deploys but never fires. Both define AND register: triggers: { preSignUp, postConfirmation }.
  • Hardcoded secrets: Using string literals instead of secret() for OAuth credentials exposes them in source control.
  • Missing scopes: Social providers default to minimal scopes — add 'email', 'profile' explicitly or user attributes won't populate.
  • Google attribute mapping: The Google claim name maps to Cognito fullname (NOT name). The attributeMapping values are plain strings, NOT objects: { email: 'email', fullname: 'name' }.
  • MFA method mismatch: Enabling sms: true in MFA requires a phone number attribute on the user pool — add phone_number to user attributes. Similarly, email: true in MFA requires an email attribute on the user pool.
  • Secrets in CI/CD: For branch environments, manage secrets through the Amplify console (App settings → Environment variables → Secrets). The ampx sandbox secret command only works for local sandbox environments.

Links

Source: SKILL.md on GitHub

No alerts16d3 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides comprehensive instructions for building applications with AWS Amplify Gen2. It includes security considerations such as the use of command-line tools for cloud resource management and the ingestion of user-provided data for infrastructure generation. These patterns are standard for developer assistant tools and are supported by best-practice recommendations within the skill, such as secure secret management.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

Signed by skilld at 7898a91. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 months ago

README badge

README badge for aws/agent-toolkit-for-aws/aws-amplify