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
},
});
OFF– MFA disabledOPTIONAL– Users can enable MFA in their settingsREQUIRED– 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/',
],
},
},
});
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.
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