This section covers the client-side development experience for password and user management. To learn more about exposing administration actions to your application, click [here](/cli/auth/admin). ## Password operations ### Change password ```ts import { Auth } from 'aws-amplify'; async function changePassword (oldPassword: string, newPassword: string) { try { const user = await Auth.currentAuthenticatedUser(); const data = await Auth.changePassword(user, oldPassword, newPassword); console.log(data); } catch(err) { console.log(err); } }; ``` ```javascript import { Auth } from 'aws-amplify'; async function changePassword (oldPassword, newPassword) { try { const user = await Auth.currentAuthenticatedUser(); const data = await Auth.changePassword(user, oldPassword, newPassword); console.log(data); } catch(err) { console.log(err); } }; ``` ### Forgot password ```ts // Send confirmation code to user's email async function forgotPassword(username: string) { try { const data = await Auth.forgotPassword(username); console.log(data); } catch(err) { console.log(err); } }; // Collect confirmation code and new password async function forgotPasswordSubmit(username: string, code: string, newPassword: string) { try { const data = await Auth.forgotPasswordSubmit(username, code, newPassword); console.log(data); } catch(err) { console.log(err); } }; ``` ```javascript import { Auth } from 'aws-amplify'; // Send confirmation code to user's email async function forgotPassword(username) { try { const data = await Auth.forgotPassword(username); console.log(data); } catch(err) { console.log(err); } } // Collect confirmation code and new password async function forgotPasswordSubmit(username, code, newPassword) { try { const data = await Auth.forgotPasswordSubmit(username, code, newPassword); console.log(data); } catch(err) { console.log(err); } } ``` ### Complete new password The user is asked to provide the new password and required attributes during the first sign-in attempt if a valid user directory is created in Amazon Cognito. During this scenario, the following method can be called to process the new password entered by the user. ```ts import { Auth } from 'aws-amplify'; async function completeNewPassword(username: string, password: string) { try { const user = await Auth.signIn(username, password); if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { const { requiredAttributes } = user.challengeParam; // the array of required attributes, e.g ['email', 'phone_number'] } const newPassword = 'newPassword' const loggedInUser = await Auth.completeNewPassword( user, // the Cognito User Object newPassword, // the new password // OPTIONAL, the required attributes { email: 'xxxx@example.com', phone_number: '1234567890' } ) console.log(loggedInUser); } catch(err) { console.log(err); } }; ``` ```js import { Auth } from 'aws-amplify'; async function completeNewPassword(username, password) { try { const user = await Auth.signIn(username, password); const newPassword = 'newPassword' if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { const { requiredAttributes } = user.challengeParam; // the array of required attributes, e.g ['email', 'phone_number'] const loggedInUser = await Auth.completeNewPassword( user, // the Cognito User Object newPassword, // the new password // OPTIONAL, the required attributes { email: 'xxxx@example.com', phone_number: '1234567890' } ) console.log(loggedInUser); } } catch(err) { console.log(err); } }; ``` ## Account recovery verification Either the phone number or the email address is required for account recovery. You can let the user verify those attributes by: ```ts // To initiate the process of verifying the attribute like 'phone_number' or 'email' async function verifyCurrentUserAttribute(attr: string) { try { await Auth.verifyCurrentUserAttribute(attr); console.log('a verification code is sent'); } catch(err) { console.log('failed with error', err); } }; // To verify attribute with the code async function verifyCurrentUserAttributeSubmit(attr: string, verificationCode: string) { try { await Auth.verifyCurrentUserAttributeSubmit(attr, verificationCode); console.log('phone_number verified'); } catch(err) { console.log('failed with error', err); } }; ``` ```javascript // To initiate the process of verifying the attribute like 'phone_number' or 'email' async function verifyCurrentUserAttribute(attr) { try { await Auth.verifyCurrentUserAttribute(attr); console.log('a verification code is sent'); } catch(err) { console.log('failed with error', err); } }; // To verify attribute with the code async function verifyCurrentUserAttributeSubmit(attr, verificationCode) { try { await Auth.verifyCurrentUserAttribute(attr, verificationCode); console.log('phone_number verified'); } catch(err) { console.log('failed with error', err); } }; ``` ## Retrieve current authenticated user You can call `Auth.currentAuthenticatedUser()` to get the current authenticated user object. ```ts import { Auth } from 'aws-amplify'; async function currentAuthenticatedUser() { try { const user = await Auth.currentAuthenticatedUser({ bypassCache: false // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data }); console.log(user); } catch(err) { console.log(err); } }; ``` ```javascript import { Auth } from 'aws-amplify'; async function currentAuthenticatedUser() { try { const user = Auth.currentAuthenticatedUser({ bypassCache: false // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data }); } catch(err) { console.log(err); } }; ``` This method can be used to check if a user is logged in when the page is loaded. It will throw an error if there is no user logged in. This method should be called after the Auth module is configured or the user is logged in. To ensure that you can listen on the auth events `configured` or `signIn`. [Learn how to listen on auth events.](/lib/utilities/hub#authentication-events) ### Retrieve attributes for current authenticated user You can also access the user's attributes like their email address, phone number, sub, or any other attributes that are associated with them from the user object returned by `Auth.currentAuthenticatedUser`. ```ts const { attributes } = await Auth.currentAuthenticatedUser(); ``` ## Retrieve current session `Auth.currentSession()` returns a `CognitoUserSession` object which contains JWT `accessToken`, `idToken`, and `refreshToken`. This method will automatically refresh the `accessToken` and `idToken` if tokens are expired and a valid `refreshToken` presented. So you can use this method to refresh the session if needed. ```javascript import { Auth } from 'aws-amplify'; async function currentSession() { try { const data = await Auth.currentSession(); console.log(data); } catch(err) { console.log(err); } }; ``` ## Managing user attributes Attributes such as name, email address, phone number help you identify individual users. The Amplify JavaScript library contains a set of APIs that can help you manage attributes in your user pool. ### Pass user attributes during sign up Amazon Cognito has a set of default standard attributes; you also have the ability to define custom attributes. Up to 50 custom attributes can be added to your user pool. You can find a [list of all the standard attributes here](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes) and [documentation for custom attributes here](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-custom-attributes). You can pass them in the `attributes` object of `Auth.signUp` function parameters: ```javascript Auth.signUp({ username: 'jdoe', password: 'mysecurerandompassword#123', attributes: { email: 'me@domain.com', phone_number: '+12128601234', // E.164 number convention given_name: 'Jane', family_name: 'Doe', nickname: 'Jane', 'custom:attribute_name': 'attribute_value' } }); ``` ### Retrieve user attributes ```ts const user = await Auth.currentAuthenticatedUser(); const { attributes } = user; ``` ### Update user attributes ```ts import { Auth } from 'aws-amplify'; async function updateUserAttributes () { try { const user = await Auth.currentAuthenticatedUser(); const result = await Auth.updateUserAttributes(user, { email: 'me@anotherdomain.com', family_name: 'Lastname' }); console.log(result); // SUCCESS } catch(err) { console.log(err); } }; ``` Note: If you change an attribute that requires confirmation (i.e. email or phone number), you will receive a confirmation code to that attribute. `Auth.updateUserAttributes()` function dispatches hub event to help identify attributes that require verification. You can listen to `updateUserAttributes` event on `auth` channel: ```javascript import { Hub } from 'aws-amplify'; Hub.listen('auth', ({payload}) => { if (payload.event === 'updateUserAttributes') { const resultObject = payload.data; } }); ``` You can learn more about how to listen to Hub events [here](https://docs.amplify.aws/lib/utilities/hub/q/platform/js/). Example of the dispatched `resultObject`: ```javascript { 'email': { isUpdated: false // indicates that attribute requires verification codeDeliveryDetails: { AttributeName: 'email', DeliveryMedium: 'EMAIL', Destination: 'm***@a...' } }, 'family_name': { isUpdated: true } } ``` If a user sends several attributes for update and one or more of them is `read_only` or doesn't exist, the Amplify JavaScript library will throw an error and dispatch `updateUserAttributes_failure` Hub event. None of the attributes in the request will be updated. ### Confirm attribute If you change the email address, you will receive a confirmation code to the new email address. Below is an example of how to confirm the new email address in your app: ```javascript const result = await Auth.verifyCurrentUserAttributeSubmit('email', ''); ``` ### Delete user attributes If you need to delete one or more user attributes, you can call `Auth.deleteUserAttributes` function from the Amplify JavaScript library: ```ts import { Auth } from 'aws-amplify'; async function deleteUserAttributes() { try { const user = await Auth.currentAuthenticatedUser(); const result = await Auth.deleteUserAttributes(user, ['family_name']); console.log(result); // SUCCESS } catch(err) { console.log(err); } }; ``` ## Updating and verifying a Cognito user email address Updating an email address using `Auth.updateUserAttributes` will require a verification of the new email address. The user will be emailed a verification code to the updated email address and your application will need to receive the verification code and send it to `Auth.verifyCurrentUserAttributeSubmit` before the email address will be updated in Cognito. The React application below implements this flow of updating the email address for the current user when the "Update Email" button is clicked, then provides a form to capture the verification code sent to the user. ```ts // App.js import { Authenticator } from '@aws-amplify/ui-react'; import '@aws-amplify/ui-react/styles.css'; import { Auth } from 'aws-amplify'; import { useState } from 'react'; async function updateUserEmail() { try { const user = await Auth.currentAuthenticatedUser(); await Auth.updateUserAttributes(user, { email: 'updatedEmail@mydomain.com' }); console.log('a verification code is sent'); } catch(err) { console.log('failed with error', err); } } async function verifyEmailValidationCode(code: string) { try { await Auth.verifyCurrentUserAttributeSubmit('email', code); console.log('email verified'); } catch(err) { console.log('failed with error', err); } } function ValidationCodeForm() { const [validationCode, setValidationCode] = useState(null); return (
); } export default function App() { const [showValidationCodeUI, setShowValidationCodeUI] = useState(false); return ( {({ signOut, user }) => (
{JSON.stringify(user?.attributes, null, 2)}
{showValidationCodeUI === false && ( )} {showValidationCodeUI === true && }
)}
); } ```
```javascript // App.js import { Authenticator } from '@aws-amplify/ui-react'; import '@aws-amplify/ui-react/styles.css'; import { Auth } from 'aws-amplify'; import { useState } from 'react'; async function updateUserEmail() { try { const user = await Auth.currentAuthenticatedUser(); await Auth.updateUserAttributes(user, { email: 'updatedEmail@mydomain.com' }); console.log('a verification code is sent'); } catch(err) { console.log('failed with error', err); } } async function verifyEmailValidationCode(code) { try { await Auth.verifyCurrentUserAttributeSubmit('email', code); console.log('email verified'); } catch(err) { console.log('failed with error', err); } } function ValidationCodeForm() { const [validationCode, setValidationCode] = useState(null); return (
); } export default function App() { const [showValidationCodeUI, setShowValidationCodeUI] = useState(false); return ( {({ signOut, user }) => (
{JSON.stringify(user.attributes, null, 2)}
{showValidationCodeUI === false && ( )} {showValidationCodeUI === true && }
)}
); } ```
## Managing security tokens > When using Authentication with AWS Amplify, you don't need to refresh Amazon Cognito tokens manually. The tokens are automatically refreshed by the library when necessary. Security Tokens like _IdToken_ or _AccessToken_ are stored in _localStorage_ for the browser and in _AsyncStorage_ for React Native. If you want to store those tokens in a more secure place or you are using Amplify in server side, then you can provide your own `storage` object to store those tokens. For example: ```ts class MyStorage { // the promise returned from sync function static syncPromise = null; // set item with the key static setItem(key: string, value: string): string; // get item with the key static getItem(key: string): string; // remove item with the key static removeItem(key: string): void; // clear out the storage static clear(): void; // If the storage operations are async(i.e AsyncStorage) // Then you need to sync those items into the memory in this method static sync(): Promise { if (!MyStorage.syncPromise) { MyStorage.syncPromise = new Promise((res, rej) => {}); } return MyStorage.syncPromise; } } // tell Auth to use your storage object Auth.configure({ storage: MyStorage }); ``` Here is the example of how to use AsyncStorage as your storage object which will show you how to sync items from AsyncStorage into Memory: ```javascript import { AsyncStorage } from 'react-native'; const MYSTORAGE_KEY_PREFIX = '@MyStorage:'; let dataMemory = {}; /** @class */ class MyStorage { static syncPromise = null; /** * This is used to set a specific item in storage */ static setItem(key, value) { AsyncStorage.setItem(MYSTORAGE_KEY_PREFIX + key, value); dataMemory[key] = value; return dataMemory[key]; } /** * This is used to get a specific key from storage */ static getItem(key) { return Object.prototype.hasOwnProperty.call(dataMemory, key) ? dataMemory[key] : undefined; } /** * This is used to remove an item from storage */ static removeItem(key) { AsyncStorage.removeItem(MYSTORAGE_KEY_PREFIX + key); return delete dataMemory[key]; } /** * This is used to clear the storage */ static clear() { dataMemory = {}; return dataMemory; } /** * Will sync the MyStorage data from AsyncStorage to storageWindow MyStorage */ static sync() { if (!MyStorage.syncPromise) { MyStorage.syncPromise = new Promise((res, rej) => { AsyncStorage.getAllKeys((errKeys, keys) => { if (errKeys) rej(errKeys); const memoryKeys = keys.filter((key) => key.startsWith(MYSTORAGE_KEY_PREFIX) ); AsyncStorage.multiGet(memoryKeys, (err, stores) => { if (err) rej(err); stores.map((result, index, store) => { const key = store[index][0]; const value = store[index][1]; const memoryKey = key.replace(MYSTORAGE_KEY_PREFIX, ''); dataMemory[memoryKey] = value; }); res(); }); }); }); } return MyStorage.syncPromise; } } Auth.configure({ storage: MyStorage }); ``` To learn more about tokens, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html).