Add sign-up in an iOS/macOS app by using native authentication
In brief
Learn how to sign up users with email one-time passcode or email and password, and collect user attributes including a username (alias), in an iOS/macOS app by using native authentication.
Documentation change
Tutorial: Add sign-up in an iOS/macOS app using native authentication
Tutorial: Add sign-up in an iOS/macOS app by using native authentication
[!INCLUDE applies-to-external-only]
This tutorial demonstrates how to sign up a user using email one-time passcode or username (email) and password, and collects user attributes in your iOS/macOS app using native authentication.
This tutorial demonstrates how to sign up a user by using email one-time passcode or username (email) and password in your iOS/macOS app by using native authentication. You also learn how to collect user attributes during sign-up, including a username (alias), and handle errors.
In this tutorial, you:
[!div class="checklist"]
- Sign up a user by using email one-time passcode or username (email) and password.
- Collect user attributes during sign-up.
- Collect user attributes during sign-up, including a username (alias).
- Handle sign-up errors.
Prerequisites
- Complete the steps in Tutorial: Prepare your iOS/macOS app for native authentication.
- If you want to collect user attributes during sign-up, configure the user attributes when you create your sign-up and sign-in user flow.
- To collect a username (alias) during sign-up, enable the Username built-in user attribute in your tenant's sign-up user flow.
Sign up a user
To sign up a user using the email one-time passcode or username (email) and password, you collect an email from the user, then send an email containing an email one-time passcode to the user. The user enters a valid email one-time passcode to validate their username.
To sign up a user by using the email one-time passcode or username (email) and password, you collect an email from the user, then send an email containing an email one-time passcode to the user. The user enters a valid email one-time passcode to validate their username.
To sign up a user, you need to:
- Collect an email from the user. Add validation to your inputs to make sure the user enters a valid email address.
- Collect a password if you sign up with username (email) and password.
- Collect a username (alias) if your app supports alias-based sign-in.
- Collect an email one-time passcode from the user.
- If needed, collect user attributes.
- Resend one-time passcode if the user doesn't receive it. } ```
- To sign up a user using **Email one-time-passcode**, we use the library's `signUp(parameters:delegate)` method, which responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
- To sign up a user using **Email one-time-passcode**, use the library's `signUp(parameters:delegate)` method, which responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
```swift
nativeAuth.signUp(parameters: parameters, delegate: self)
```
In the `signUp(parameters:delegate)` method, we pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address from the submission form alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
In the `signUp(parameters:delegate)` method, pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address from the submission form alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
- To sign up a user using **Email with password**, use the following code snippets:
}
```
we use the library's `signUp(parameters:delegate)` method, which responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
The library's `signUp(parameters:delegate)` method responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
```swift
nativeAuth.signUp(parameters: parameters, delegate: self)
```
In the `signUp(parameters:delegate)` method, we pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address and their password alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
In the `signUp(parameters:delegate)` method, pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address and their password alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
- To implement `SignUpStartDelegate` protocol as an extension to our class, use:
- To implement the `SignUpStartDelegate` protocol as an extension to your class, use:
```swift
extension ViewController: SignUpStartDelegate {
}
```
The call to `signUp(parameters:delegate)`results in a call to either `onSignUpCodeRequired()` or `onSignUpStartError()` delegate methods. The `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Along with some details of where the code has been sent, and how many digits it contains, this delegate method also has a `newState` parameter of type `SignUpCodeRequiredState`, which gives us access to two new methods:
The call to `signUp(parameters:delegate)` results in a call to either `onSignUpCodeRequired()` or `onSignUpStartError()` delegate methods. The `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Along with some details of where the code has been sent, and how many digits it contains, this delegate method also has a `newState` parameter of type `SignUpCodeRequiredState`, which gives you access to two new methods:
- `submitCode(code:delegate)`
- `resendCode(delegate)`
To submit the code that the user supplied us with, use:
To submit the code that the user supplied, use:
```swift
newState.submitCode(code: userSuppliedCode, delegate: self)
```
- To implement `SignUpVerifyCodeDelegate` protocol as an extension to our class, use:
- To implement the `SignUpVerifyCodeDelegate` protocol as an extension to your class, use:
```swift
extension ViewController: SignUpVerifyCodeDelegate {
}
```
The `submitCode(code:delegate)` accepts a delegate parameter and we must implement the required methods in the `SignUpVerifyCodeDelegate` protocol. In the most common scenario, we receive a call to `onSignUpCompleted(newState)` indicating that the user has been signed up and the flow is complete.
The `submitCode(code:delegate)` accepts a delegate parameter and you must implement the required methods in the `SignUpVerifyCodeDelegate` protocol. In the most common scenario, you receive a call to `onSignUpCompleted(newState)` indicating that the user has been signed up and the flow is complete.
Collect user attributes during sign-up
The `signUp(parameters:delegate)`results in a call to either `onSignUpCodeRequired()` or `onSignUpStartError()` delegate methods, or in a call to `onSignUpAttributesInvalid(attributeNames: [String])` if it's implemented in the delegate.
- To implement the
SignUpStartDelegateprotocol as an extension to our class, use the following code snippet:
- To implement the
SignUpStartDelegateprotocol as an extension to your class, use the following code snippet:
```swift
extension ViewController: SignUpStartDelegate {
}
```
If the attributes are invalid, the method `onSignUpAttributesInvalid(attributeNames: [String])` is called. In this case, we display the list of invalid attributes to the user. Otherwise, the `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Apart from details such as the recipient of the code, and number of digits of the code, this delegate method has a `newState` parameter of type `SignUpCodeRequiredState`, which gives us access to two new methods:
If the attributes are invalid, the method `onSignUpAttributesInvalid(attributeNames: [String])` is called. In this case, display the list of invalid attributes to the user. Otherwise, the `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Apart from details such as the recipient of the code, and number of digits of the code, this delegate method has a `newState` parameter of type `SignUpCodeRequiredState`, which gives you access to two new methods:
- `submitCode(code:delegate)`
- `resendCode(delegate)`
User attributes across one or more pages
To spread the attributes across one or more pages, we must set the attributes we intend to collect across different pages as mandatory in the customer identity and access management (CIAM) tenant configuration.
To spread the attributes across one or more pages, set the attributes you intend to collect across different pages as mandatory in the customer identity and access management (CIAM) tenant configuration.
We call signUp(parameters:delegate) without passing any attributes in the MSALNativeAuthSignUpParameters instance. The next step will be to call newState.submitCode(code: userSuppliedCode, delegate: self) to verify user's email.
Call signUp(parameters:delegate) without passing any attributes in the MSALNativeAuthSignUpParameters instance. The next step is to call newState.submitCode(code: userSuppliedCode, delegate: self) to verify the user's email.
We implement the SignUpVerifyCodeDelegate protocol as an extension to our class as before, but this time we must implement the optional method onSignUpAttributesRequired(attributes:newState) in addition to the required methods:
Implement the SignUpVerifyCodeDelegate protocol as an extension to your class as before, but this time you must implement the optional method onSignUpAttributesRequired(attributes:newState) in addition to the required methods:
extension ViewController: SignUpVerifyCodeDelegate {
}
This delegate method has a newState parameter of type SignUpAttributesRequiredState, which gives us access to a new method:
This delegate method has a newState parameter of type SignUpAttributesRequiredState, which gives you access to a new method:
submitAttributes(attributes:delegate)
To submit the attributes that the user supplied us with, use the following code snippet:
To submit the attributes that the user supplied, use the following code snippet:
let attributes = [
newState.submitAttributes(attributes: attributes, delegate: self)
We'll also implement the SignUpAttributesRequiredDelegate protocol as an extension to our class:
Also implement the SignUpAttributesRequiredDelegate protocol as an extension to your class:
extension ViewController: SignUpAttributesRequiredDelegate {
- `onSignUpAttributesInvalid`: indicates that one or more attributes that were sent failed input validation. This error contains an attributeNames parameter, which is a list of all attributes that were sent by the developer that failed input validation.
- `onSignUpAttributesRequired`: indicates that the server requires one or more attributes to be sent, before the user account can be created. This happens when one or more attributes is set as mandatory in the tenant configuration. This result contains attributes parameter, which is a list of `MSALNativeAuthRequiredAttribute` objects, which outline details about the user attributes that the API requires.
Both delegate methods contain a new state reference. We use the newState parameter to call submitAttributes(attributes:delegate) again with the new attributes.
Both delegate methods contain a new state reference. Use the newState parameter to call submitAttributes(attributes:delegate) again with the new attributes.
Collect a username (alias) during sign-up
The username (alias) is a special user attribute. Like other attributes such as city or country, you collect it during sign-up. Unlike those attributes, the user can later use the alias to sign in. The alias (for example, "johndoe") gives users a shorter, friendlier way to sign in than their email address.
The username (alias) doesn't replace the username (email). During sign-up, the app must always collect the username (email) as the primary identifier, and it collects the alias as an attribute alongside the email. At sign-in, the user can then choose to sign in with either their username (email) or their username (alias).
When the Username built-in user attribute is enabled in your sign-up user flow, the SDK accepts it through the same attributes dictionary used for other attributes, as the flatusername key. You can pass the username (alias) directly in the signUp call so the user doesn't need to go through a separate attributes-required step.
To collect a username (alias), add an input field for the username in your sign-up UI alongside the email field, then pass the alias as an attribute in the sign-up call:
guard let email = emailTextField.text, !email.isEmpty,
let password = passwordTextField.text, !password.isEmpty,
let username = usernameTextField.text, !username.isEmpty else {
showResultText("Please fill in all fields")
return
}
let attributes: [String: Any] = [
"flatusername": username
]
let parameters = MSALNativeAuthSignUpParameters(username: email)
parameters.password = password
parameters.attributes = attributes
nativeAuth.signUp(parameters: parameters, delegate: self)
For email one-time passcode flows (without password), pass the attributes without setting a password:
let parameters = MSALNativeAuthSignUpParameters(username: email)
parameters.attributes = attributes
nativeAuth.signUp(parameters: parameters, delegate: self)
When handling errors for username (alias) sign-up, the error.isUserAlreadyExists property also covers a duplicate alias, and error.isInvalidAttributes surfaces an invalid alias value.
Handle sign-up errors
During sign-up, not every action succeeds. For example, the user might try to sign up with an email address that's already in use, or submit an invalid code.
During sign-up, not every action succeeds. For example, the user might try to sign up with an email address that's already in use, or submit an invalid code.
In our earlier implementation of SignUpStartDelegate protocol, we simply displayed the error when we handled the onSignUpStartError(error) delegate function.
In the earlier implementation of the SignUpStartDelegate protocol, the error was simply displayed when handling the onSignUpStartError(error) delegate function.
To enhance the user experience by managing the particular error type, use the following code snippet:
Optional: Sign in after a sign-up flow
After a successful sign-up flow, you can sign-in a user without initiating a sign-in flow. Learn more in the Tutorial: Sign in user automatically after sign-up in an iOS/macOS app article.
After a successful sign-up flow, you can sign in a user without initiating a sign-in flow. If the user signed up with a username (alias), they can sign in by using either their email address or their alias. Learn more in the Tutorial: Sign in user automatically after sign-up in an iOS/macOS app article.
Next step
diff --git a/docs/identity-platform/tutorial-native-authentication-ios-macos-sign-up.md b/docs/identity-platform/tutorial-native-authentication-ios-macos-sign-up.md
index 9d86903584e..a0c75bc632d 100644
--- a/docs/identity-platform/tutorial-native-authentication-ios-macos-sign-up.md
+++ b/docs/identity-platform/tutorial-native-authentication-ios-macos-sign-up.md
@@ -1,38 +1,38 @@
---
-title: Add sign-up in native iOS/macOS app
-description: Learn how to add sign-up using email one-time passcode or email and password, and collect user attributes in an iOS/macOS mobile app using native authentication.
-
+title: Add sign-up in an iOS/macOS app by using native authentication
+description: Learn how to sign up users with email one-time passcode or email and password, and collect user attributes including a username (alias), in an iOS/macOS app by using native authentication.
manager: pmwongera
-
ms.service: identity-platform
-
ms.subservice: external
ms.topic: tutorial
-ms.date: 08/19/2024
-ms.custom:
-#Customer intent: As a dev, devops, I want to learn how to add sign-up using email one-time passcode or email and password, and collect user attributes in an iOS/macOS mobile app using native authentication.
+ms.date: 06/17/2026
+
+#Customer intent: As a developer, I want to add sign-up with email one-time passcode or email and password, and collect user attributes including a username (alias), in my iOS/macOS app by using native authentication so that users can create accounts with flexible identity options.
---
-# Tutorial: Add sign-up in an iOS/macOS app using native authentication
+# Tutorial: Add sign-up in an iOS/macOS app by using native authentication
[!INCLUDE [applies-to-external-only](../external-id/includes/applies-to-external-only.md)]
-This tutorial demonstrates how to sign up a user using email one-time passcode or username (email) and password, and collects user attributes in your iOS/macOS app using native authentication.
+This tutorial demonstrates how to sign up a user by using email one-time passcode or username (email) and password in your iOS/macOS app by using native authentication. You also learn how to collect user attributes during sign-up, including a username (alias), and handle errors.
+
+In this tutorial, you:
> [!div class="checklist"]
>
> - Sign up a user by using email one-time passcode or username (email) and password.
-> - Collect user attributes during sign-up.
+> - Collect user attributes during sign-up, including a username (alias).
> - Handle sign-up errors.
## Prerequisites
-- [Tutorial: Prepare your iOS/macOS app for native authentication](tutorial-native-authentication-prepare-ios-macos-app.md).
+- Complete the steps in [Tutorial: Prepare your iOS/macOS app for native authentication](tutorial-native-authentication-prepare-ios-macos-app.md).
- If you want to collect user attributes during sign-up, configure the user attributes when you [create your sign-up and sign-in user flow](../external-id/customers/how-to-user-flow-sign-up-sign-in-customers.md).
+- To collect a username (alias) during sign-up, enable the **Username** built-in user attribute in your tenant's sign-up user flow.
## Sign up a user
-To sign up a user using the email one-time passcode or username (email) and password, you collect an email from the user, then send an email containing an email one-time passcode to the user. The user enters a valid email one-time passcode to validate their username.
+To sign up a user by using the email one-time passcode or username (email) and password, you collect an email from the user, then send an email containing an email one-time passcode to the user. The user enters a valid email one-time passcode to validate their username.
To sign up a user, you need to:
@@ -40,6 +40,7 @@ To sign up a user, you need to:
- Collect an email from the user. Add validation to your inputs to make sure the user enters a valid email address.
- Collect a password if you sign up with username (email) and password.
+ - Collect a username (alias) if your app supports alias-based sign-in.
- Collect an email one-time passcode from the user.
- If needed, collect user attributes.
- Resend one-time passcode if the user doesn't receive it.
@@ -59,13 +60,13 @@ To sign up a user, you need to:
}
```
- - To sign up a user using **Email one-time-passcode**, we use the library's `signUp(parameters:delegate)` method, which responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
+ - To sign up a user using **Email one-time-passcode**, use the library's `signUp(parameters:delegate)` method, which responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
```swift
nativeAuth.signUp(parameters: parameters, delegate: self)
```
- In the `signUp(parameters:delegate)` method, we pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address from the submission form alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
+ In the `signUp(parameters:delegate)` method, pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address from the submission form alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
- To sign up a user using **Email with password**, use the following code snippets:
@@ -82,16 +83,16 @@ To sign up a user, you need to:
}
```
- we use the library's `signUp(parameters:delegate)` method, which responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
+ The library's `signUp(parameters:delegate)` method responds asynchronously by calling one of the methods on the passed delegate object, which must implement the `SignUpStartDelegate` protocol. The following line of code initiates the user sign-up process:
```swift
nativeAuth.signUp(parameters: parameters, delegate: self)
```
- In the `signUp(parameters:delegate)` method, we pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address and their password alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
+ In the `signUp(parameters:delegate)` method, pass a `MSALNativeAuthSignUpParameters` instance containing the user's email address and their password alongside the delegate (a class that implements the `SignUpStartDelegate` protocol).
- - To implement `SignUpStartDelegate` protocol as an extension to our class, use:
+ - To implement the `SignUpStartDelegate` protocol as an extension to your class, use:
```swift
extension ViewController: SignUpStartDelegate {
@@ -110,18 +111,18 @@ To sign up a user, you need to:
}
```
- The call to `signUp(parameters:delegate)`results in a call to either `onSignUpCodeRequired()` or `onSignUpStartError()` delegate methods. The `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Along with some details of where the code has been sent, and how many digits it contains, this delegate method also has a `newState` parameter of type `SignUpCodeRequiredState`, which gives us access to two new methods:
+ The call to `signUp(parameters:delegate)` results in a call to either `onSignUpCodeRequired()` or `onSignUpStartError()` delegate methods. The `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Along with some details of where the code has been sent, and how many digits it contains, this delegate method also has a `newState` parameter of type `SignUpCodeRequiredState`, which gives you access to two new methods:
- `submitCode(code:delegate)`
- `resendCode(delegate)`
- To submit the code that the user supplied us with, use:
+ To submit the code that the user supplied, use:
```swift
newState.submitCode(code: userSuppliedCode, delegate: self)
```
- - To implement `SignUpVerifyCodeDelegate` protocol as an extension to our class, use:
+ - To implement the `SignUpVerifyCodeDelegate` protocol as an extension to your class, use:
```swift
extension ViewController: SignUpVerifyCodeDelegate {
@@ -135,7 +136,7 @@ To sign up a user, you need to:
}
```
- The `submitCode(code:delegate)` accepts a delegate parameter and we must implement the required methods in the `SignUpVerifyCodeDelegate` protocol. In the most common scenario, we receive a call to `onSignUpCompleted(newState)` indicating that the user has been signed up and the flow is complete.
+ The `submitCode(code:delegate)` accepts a delegate parameter and you must implement the required methods in the `SignUpVerifyCodeDelegate` protocol. In the most common scenario, you receive a call to `onSignUpCompleted(newState)` indicating that the user has been signed up and the flow is complete.
## Collect user attributes during sign-up
@@ -157,7 +158,7 @@ Whether you sign up a user using email one-time passcode or username (email) and
The `signUp(parameters:delegate)`results in a call to either `onSignUpCodeRequired()` or `onSignUpStartError()` delegate methods, or in a call to `onSignUpAttributesInvalid(attributeNames: [String])` if it's implemented in the delegate.
-1. To implement the `SignUpStartDelegate` protocol as an extension to our class, use the following code snippet:
+1. To implement the `SignUpStartDelegate` protocol as an extension to your class, use the following code snippet:
```swift
extension ViewController: SignUpStartDelegate {
@@ -180,18 +181,18 @@ Whether you sign up a user using email one-time passcode or username (email) and
}
```
- If the attributes are invalid, the method `onSignUpAttributesInvalid(attributeNames: [String])` is called. In this case, we display the list of invalid attributes to the user. Otherwise, the `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Apart from details such as the recipient of the code, and number of digits of the code, this delegate method has a `newState` parameter of type `SignUpCodeRequiredState`, which gives us access to two new methods:
+ If the attributes are invalid, the method `onSignUpAttributesInvalid(attributeNames: [String])` is called. In this case, display the list of invalid attributes to the user. Otherwise, the `onSignUpCodeRequired(newState:sentTo:channelTargetType:codeLength)` is called to indicate that a code has been sent to verify the user's email address. Apart from details such as the recipient of the code, and number of digits of the code, this delegate method has a `newState` parameter of type `SignUpCodeRequiredState`, which gives you access to two new methods:
- `submitCode(code:delegate)`
- `resendCode(delegate)`
### User attributes across one or more pages
-To spread the attributes across one or more pages, we must set the attributes we intend to collect across different pages as mandatory in the customer identity and access management (CIAM) tenant configuration.
+To spread the attributes across one or more pages, set the attributes you intend to collect across different pages as mandatory in the customer identity and access management (CIAM) tenant configuration.
-We call `signUp(parameters:delegate)` without passing any attributes in the `MSALNativeAuthSignUpParameters` instance. The next step will be to call `newState.submitCode(code: userSuppliedCode, delegate: self)` to verify user's email.
+Call `signUp(parameters:delegate)` without passing any attributes in the `MSALNativeAuthSignUpParameters` instance. The next step is to call `newState.submitCode(code: userSuppliedCode, delegate: self)` to verify the user's email.
-We implement the `SignUpVerifyCodeDelegate` protocol as an extension to our class as before, but this time we must implement the optional method `onSignUpAttributesRequired(attributes:newState)` in addition to the required methods:
+Implement the `SignUpVerifyCodeDelegate` protocol as an extension to your class as before, but this time you must implement the optional method `onSignUpAttributesRequired(attributes:newState)` in addition to the required methods:
```swift
extension ViewController: SignUpVerifyCodeDelegate {
@@ -209,11 +210,11 @@ extension ViewController: SignUpVerifyCodeDelegate {
}
```
-This delegate method has a `newState` parameter of type `SignUpAttributesRequiredState`, which gives us access to a new method:
+This delegate method has a `newState` parameter of type `SignUpAttributesRequiredState`, which gives you access to a new method:
- `submitAttributes(attributes:delegate)`
-To submit the attributes that the user supplied us with, use the following code snippet:
+To submit the attributes that the user supplied, use the following code snippet:
```swift
let attributes = [
@@ -224,7 +225,7 @@ let attributes = [
newState.submitAttributes(attributes: attributes, delegate: self)
```
-We'll also implement the `SignUpAttributesRequiredDelegate` protocol as an extension to our class:
+Also implement the `SignUpAttributesRequiredDelegate` protocol as an extension to your class:
```swift
extension ViewController: SignUpAttributesRequiredDelegate {
@@ -251,14 +252,53 @@ When the user doesn't provide all the required attributes, or the attributes are
- `onSignUpAttributesInvalid`: indicates that one or more attributes that were sent failed input validation. This error contains an attributeNames parameter, which is a list of all attributes that were sent by the developer that failed input validation.
- `onSignUpAttributesRequired`: indicates that the server requires one or more attributes to be sent, before the user account can be created. This happens when one or more attributes is set as mandatory in the tenant configuration. This result contains attributes parameter, which is a list of `MSALNativeAuthRequiredAttribute` objects, which outline details about the user attributes that the API requires.
-Both delegate methods contain a new state reference. We use the `newState` parameter to call `submitAttributes(attributes:delegate)` again with the new attributes.
+Both delegate methods contain a new state reference. Use the `newState` parameter to call `submitAttributes(attributes:delegate)` again with the new attributes.
+
+
+## Collect a username (alias) during sign-up
+
+The username (alias) is a special user attribute. Like other attributes such as city or country, you collect it during sign-up. Unlike those attributes, the user can later use the alias to sign in. The alias (for example, "johndoe") gives users a shorter, friendlier way to sign in than their email address.
+
+The username (alias) doesn't replace the username (email). During sign-up, the app must always collect the username (email) as the primary identifier, and it collects the alias as an attribute alongside the email. At sign-in, the user can then choose to sign in with either their username (email) or their username (alias).
+
+When the **Username** built-in user attribute is enabled in your sign-up user flow, the SDK accepts it through the same attributes dictionary used for other attributes, as the `flatusername` key. You can pass the username (alias) directly in the `signUp` call so the user doesn't need to go through a separate attributes-required step.
+
+To collect a username (alias), add an input field for the username in your sign-up UI alongside the email field, then pass the alias as an attribute in the sign-up call:
+
+```swift
+guard let email = emailTextField.text, !email.isEmpty,
+ let password = passwordTextField.text, !password.isEmpty,
+ let username = usernameTextField.text, !username.isEmpty else {
+ showResultText("Please fill in all fields")
+ return
+}
+
+let attributes: [String: Any] = [
+ "flatusername": username
+]
+
+let parameters = MSALNativeAuthSignUpParameters(username: email)
+parameters.password = password
+parameters.attributes = attributes
+nativeAuth.signUp(parameters: parameters, delegate: self)
+```
+
+For email one-time passcode flows (without password), pass the attributes without setting a password:
+
+```swift
+let parameters = MSALNativeAuthSignUpParameters(username: email)
+parameters.attributes = attributes
+nativeAuth.signUp(parameters: parameters, delegate: self)
+```
+
+When handling errors for username (alias) sign-up, the `error.isUserAlreadyExists` property also covers a duplicate alias, and `error.isInvalidAttributes` surfaces an invalid alias value.
## Handle sign-up errors
-During sign-up, not every action succeeds. For example, the user might try to sign up with an email address that's already in use, or submit an invalid code.
+During sign-up, not every action succeeds. For example, the user might try to sign up with an email address that's already in use, or submit an invalid code.
-In our earlier implementation of `SignUpStartDelegate` protocol, we simply displayed the error when we handled the `onSignUpStartError(error)` delegate function.
+In the earlier implementation of the `SignUpStartDelegate` protocol, the error was simply displayed when handling the `onSignUpStartError(error)` delegate function.
To enhance the user experience by managing the particular error type, use the following code snippet:
@@ -278,7 +318,7 @@ func onSignUpStartError(error: MSAL.SignUpStartError) {
## Optional: Sign in after a sign-up flow
-After a successful sign-up flow, you can sign-in a user without initiating a sign-in flow. Learn more in the [Tutorial: Sign in user automatically after sign-up in an iOS/macOS app](tutorial-native-authentication-ios-macos-sign-in-user-after-sign-up.md) article.
+After a successful sign-up flow, you can sign in a user without initiating a sign-in flow. If the user signed up with a username (alias), they can sign in by using either their email address or their alias. Learn more in the [Tutorial: Sign in user automatically after sign-up in an iOS/macOS app](tutorial-native-authentication-ios-macos-sign-in-user-after-sign-up.md) article.
## Next step