I’m stuck here.
I’m working on Swift with Amplify version 1.0.
I’ve got a workflow that involves allowing the user to change their account email from the app.
Updating the email works, but according to the Amplify Docs, since the email is an attribute that requires verification, I need to prompt the user to enter a verification code which they would receive at the new email address. However, when the code received via email is entered by the user, and the confirmAttribute function is called with the entered code that the user receives, I get a codeExpired response? It doesn’t make any sense and I’ve been working on this for 3 days and can’t figure it out.
In a nutshell:
- User wants to change their email address.
- They enter their new email address and hit save, upon which the app calls updateAmplifyAttributes().
- The attribute requires verification. Amplify sends an email to the user’s new email address. The user sees the email and the code provided and enters it in the app.
- The app calls confirmAttributes() with the user’s provided code which matches the one that Amplify sent via email.
- Upon this, aws cognito shows the email verified in the aws console, however, the return from the function in the app is still that the “Code Expired”.
- Despite the fact that the response is “Code Expired”, the user’s email is considered “verified” on Cognito at that point, so everything from the cloud side is working correctly, but from the app’s side, we’re capturing a “Code Expired” error. Something I can work around, but it’s not a comfortable thing to work around.
What’s the deal here? I’m following the docs religiously but nothing seems to work.
https://docs.amplify.aws/gen1/swift/build-a-backend/auth/managing-attributes/
Here’s the code bits:
func updateAmplifyAttributes(updateAttributes: AmplifyUpdateAttributesRequestModel) async -> UpdateAttributesResult {
var userAttributes = [AuthUserAttribute]()
userAttributes.append(AuthUserAttribute(.familyName, value: updateAttributes.lastName))
userAttributes.append(AuthUserAttribute(.givenName, value: updateAttributes.firstName))
userAttributes.append(AuthUserAttribute(.phoneNumber, value: updateAttributes.phoneNumber))
userAttributes.append(AuthUserAttribute(.custom("street"), value: updateAttributes.streetAddress))
userAttributes.append(AuthUserAttribute(.custom("city"), value: updateAttributes.city))
userAttributes.append(AuthUserAttribute(.custom("state"), value: updateAttributes.state))
userAttributes.append(AuthUserAttribute(.custom("zip"), value: updateAttributes.zip))
userAttributes.append(AuthUserAttribute(.custom("country"), value: updateAttributes.country))
userAttributes.append(AuthUserAttribute(.custom("appsource"), value: StringConstants.appSource))
userAttributes.append(AuthUserAttribute(.email, value: updateAttributes.email))
do {
let updateResult = try await Amplify.Auth.update(userAttributes: userAttributes)
for (attributeKey, result) in updateResult {
switch result.nextStep {
case .confirmAttributeWithCode(let deliveryDetails, _):
print("Confirm the attribute (attributeKey) with details sent to - (deliveryDetails)")
return .confirmationRequired(attributeKey.rawValue)
case .done:
print("Update for (attributeKey) completed")
}
}
return .success // If all updates are completed successfully
} catch let error as AuthError {
print("Update attribute failed with error (error)")
return .failure("Update attribute failed with error (error.localizedDescription)")
} catch {
print("Unexpected error: (error)")
return .failure("Unexpected error: (error.localizedDescription)")
}
}
func confirmAttributes(updateAttributes: AmplifyUpdateAttributesRequestModel, authCode: String) async throws {
do {
// No need to assign to a constant, just call the method directly
try await Amplify.Auth.confirm(
userAttribute: .email,
confirmationCode: authCode
)
print("Attribute verified and confirmed.")
} catch let error as AuthError {
print("Update attribute failed with error (error)")
throw error // Re-throw the error if needed
} catch {
print("Unexpected error: (error)")
throw error // Re-throw unexpected errors if needed
}
}