Configuring the Auth Resource

Let's dive deeper into the auth resource configuration and understand all the options available for customizing authentication.

Basic Auth Configuration

We created this in Module 3. Let's review and expand it:

// amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';

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

This minimal configuration creates a Cognito User Pool where:

  • Users sign in with their email address
  • Email verification is required
  • Default password policy is applied

Configuration Options

Login Methods

export const auth = defineAuth({
  loginWith: {
    email: true,        // Sign in with email
    // OR
    phone: true,        // Sign in with phone number
    // OR use a username
    // (when both email and phone are false)
  },
});

User Attributes

User attributes are pieces of information stored for each user. Some are standard (defined by OpenID Connect), and you can add custom ones:

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
  userAttributes: {
    // Standard attributes
    preferredUsername: {
      required: false,
      mutable: true,
    },
    givenName: {
      required: true,
      mutable: true,
    },
    familyName: {
      required: true,
      mutable: true,
    },
    // Custom attributes
    'custom:company': {
      dataType: 'String',
      mutable: true,
    },
    'custom:department': {
      dataType: 'String',
      mutable: true,
    },
  },
});

Standard Attributes Reference

Attribute Description
email Email address (auto-included when loginWith email is true)
phone Phone number in E.164 format
preferredUsername Display name chosen by user
givenName First name
familyName Last name
birthdate Date of birth (YYYY-MM-DD format)
address Physical address
locale User's locale (e.g., en-US)
zoneinfo Time zone (e.g., America/New_York)
picture URL to profile picture

Multi-Factor Authentication (MFA)

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
  multifactor: {
    mode: 'OPTIONAL',  // 'OFF' | 'OPTIONAL' | 'REQUIRED'
    sms: true,         // Enable SMS-based MFA
    totp: true,        // Enable authenticator app MFA
  },
});
💡
MFA Modes
  • OFF – MFA disabled
  • OPTIONAL – Users can enable MFA in their settings
  • REQUIRED – All users must set up MFA

Social Sign-In (OAuth)

To enable Google, Facebook, Apple, or Amazon sign-in, you need to set up OAuth apps with those providers first, then configure Amplify:

export const auth = defineAuth({
  loginWith: {
    email: true,
    externalProviders: {
      google: {
        clientId: process.env.GOOGLE_CLIENT_ID!,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      },
      facebook: {
        clientId: process.env.FACEBOOK_APP_ID!,
        clientSecret: process.env.FACEBOOK_APP_SECRET!,
      },
      signInWithApple: {
        clientId: process.env.APPLE_CLIENT_ID!,
        teamId: process.env.APPLE_TEAM_ID!,
        keyId: process.env.APPLE_KEY_ID!,
        privateKey: process.env.APPLE_PRIVATE_KEY!,
      },
      callbackUrls: [
        'http://localhost:3000/auth/callback',
        'https://yourdomain.com/auth/callback',
      ],
      logoutUrls: [
        'http://localhost:3000/',
        'https://yourdomain.com/',
      ],
    },
  },
});
⚠️
Environment Variables

Store OAuth secrets in environment variables, never in code. Create a .env file (gitignored) for local development and configure secrets in Amplify Console for production.

Complete Example

Here's a more complete auth configuration for a real application:

// amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
  
  // User profile attributes
  userAttributes: {
    preferredUsername: {
      required: false,
      mutable: true,
    },
    givenName: {
      required: false,
      mutable: true,
    },
    familyName: {
      required: false,
      mutable: true,
    },
  },
  
  // Optional: Customize account recovery
  accountRecovery: 'EMAIL_ONLY',
  
  // Optional: Customize email sender
  senderName: 'Amplify Todo App',
});

Creating an Auth Composable

To use authentication in your Vue components, create a composable that wraps Amplify's auth functions:

Create composables/useAmplifyAuth.ts:

// composables/useAmplifyAuth.ts
import {
  getCurrentUser,
  signIn,
  signUp,
  signOut,
  confirmSignUp,
  type SignInInput,
  type SignUpInput,
} from 'aws-amplify/auth';

interface User {
  userId: string;
  username: string;
  signInDetails?: {
    loginId?: string;
  };
}

export const useAmplifyAuth = () => {
  // Reactive state (shared across components)
  const user = useState<User | null>('amplify-user', () => null);
  const isLoading = useState('amplify-auth-loading', () => false);
  const error = useState<string | null>('amplify-auth-error', () => null);

  // Computed property for authentication status
  const isAuthenticated = computed(() => !!user.value);

  // Check if user is already signed in
  const checkAuth = async (): Promise<boolean> => {
    isLoading.value = true;
    error.value = null;
    try {
      const currentUser = await getCurrentUser();
      user.value = currentUser;
      return true;
    } catch {
      user.value = null;
      return false;
    } finally {
      isLoading.value = false;
    }
  };

  // Sign in with email and password
  const handleSignIn = async (input: SignInInput) => {
    isLoading.value = true;
    error.value = null;
    try {
      const result = await signIn(input);
      if (result.isSignedIn) {
        await checkAuth();
      }
      return result;
    } catch (err: any) {
      error.value = err.message || 'Sign in failed';
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // Sign up a new user
  const handleSignUp = async (input: SignUpInput) => {
    isLoading.value = true;
    error.value = null;
    try {
      const result = await signUp(input);
      return result;
    } catch (err: any) {
      error.value = err.message || 'Sign up failed';
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // Confirm sign up with verification code
  const handleConfirmSignUp = async (
    username: string,
    confirmationCode: string
  ) => {
    isLoading.value = true;
    error.value = null;
    try {
      const result = await confirmSignUp({
        username,
        confirmationCode,
      });
      return result;
    } catch (err: any) {
      error.value = err.message || 'Confirmation failed';
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // Sign out the current user
  const handleSignOut = async () => {
    isLoading.value = true;
    error.value = null;
    try {
      await signOut();
      user.value = null;
    } catch (err: any) {
      error.value = err.message || 'Sign out failed';
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // Clear any error messages
  const clearError = () => {
    error.value = null;
  };

  return {
    // State
    user,
    isLoading,
    error,
    isAuthenticated,
    
    // Methods
    checkAuth,
    signIn: handleSignIn,
    signUp: handleSignUp,
    confirmSignUp: handleConfirmSignUp,
    signOut: handleSignOut,
    clearError,
  };
};

Using the Composable

Now you can use authentication in any component:

<script setup lang="ts">
const { user, isAuthenticated, signIn, signOut, error } = useAmplifyAuth();

const email = ref('');
const password = ref('');

const handleLogin = async () => {
  try {
    await signIn({ username: email.value, password: password.value });
    // Navigate to dashboard or home
    navigateTo('/');
  } catch (e) {
    // Error is already set in composable
    console.error('Login failed');
  }
};
</script>

<template>
  <div v-if="isAuthenticated">
    Welcome, {{ user?.signInDetails?.loginId }}!
    <button @click="signOut">Sign Out</button>
  </div>
  <form v-else @submit.prevent="handleLogin">
    <input v-model="email" type="email" placeholder="Email" />
    <input v-model="password" type="password" placeholder="Password" />
    <p v-if="error" class="text-red-500">{{ error }}</p>
    <button type="submit">Sign In</button>
  </form>
</template>

Updating the Sandbox

After modifying amplify/auth/resource.ts, the sandbox will automatically detect the changes and redeploy. Watch the terminal running npx ampx sandbox for deployment status.

⚠️
Some Changes Require Recreation

Certain auth changes (like modifying required attributes) may require deleting and recreating the User Pool. The CLI will warn you if this is needed.

Summary

  • Auth resource is configured in amplify/auth/resource.ts
  • You can customize login methods, user attributes, MFA, and social providers
  • Create a composable to wrap auth functions for Vue components
  • The sandbox automatically redeploys when you save changes