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.
What Entra admins need to know
Review the documentation change to determine whether it affects tenant configuration, security posture, or rollout plans.
This editorial summary was generated by AI from the documentation changes. Verify important details in the full Microsoft Learn article.
Documentation change
The comparison below is an extract of the Microsoft Learn article showing only the changed content. Open the full article for complete context.
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 by using email one-time passcode or username (email) and password, and collects user attributespassword 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.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 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:
```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).
- To sign up a user using **Email with password**, use the following code snippets:
}
```
we use theThe library's `signUp(parameters:delegate)` method, whichmethod 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).
- To implement the `SignUpStartDelegate` protocol as an extension to ouryour 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 usyou access to two new methods:
- `submitCode(code:delegate)`
- `resendCode(delegate)`
To submit the code that the user supplied us with,supplied, use:
```swift
newState.submitCode(code: userSuppliedCode, delegate: self)
```
- To implement the `SignUpVerifyCodeDelegate` protocol as an extension to ouryour class, use:
```swift
extension ViewController: SignUpVerifyCodeDelegate {
}
```
The `submitCode(code:delegate)` accepts a delegate parameter and weyou must implement the required methods in the `SignUpVerifyCodeDelegate` protocol. In the most common scenario, weyou 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 toouryour class, use the following code snippet:extension ViewController: SignUpStartDelegate { }If the attributes are invalid, the method
onSignUpAttributesInvalid(attributeNames: [String])is called. In this case,wedisplay the list of invalid attributes to the user. Otherwise, theonSignUpCodeRequired(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 anewStateparameter of typeSignUpCodeRequiredState, which givesusyou 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 weyou intend to collect across different pages as mandatory in the customer identity and access management (CIAM) tenant configuration.
We callCall signUp(parameters:delegate) without passing any attributes in the MSALNativeAuthSignUpParameters instance. The next step will beis to call newState.submitCode(code: userSuppliedCode, delegate: self) to verify the user's email.
We implementImplement the SignUpVerifyCodeDelegate protocol as an extension to ouryour class as before, but this time weyou 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 usyou access to a new method:
submitAttributes(attributes:delegate)
To submit the attributes that the user supplied us with,supplied, use the following code snippet:
let attributes = [
newState.submitAttributes(attributes: attributes, delegate: self)
We'll alsoAlso implement the SignUpAttributesRequiredDelegate protocol as an extension to ouryour 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 useUse 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:
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.
In ourthe earlier implementation of `SignUpStartDelegate`the SignUpStartDelegate protocol, wethe error was simply displayed when handling the error when we handled the `onSignUpStartError(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-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)Tutorial: Sign in user automatically after sign-up in an iOS/macOS app article.
##
Next step
@@ -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 