iOS API Reference
iOS API Reference
#Overview
The Magic SDK for iOS is your entry-point to secure, passwordless authentication for your mobile app. This guide will cover some important topics for getting started with iOS APIs and to make the most of Magic's features.
#Getting Started
The Magic class is the entry-point to the Magic SDK. It must be instantiated with a Magic publishable key.
#Performance improvement (optional)
We use service workers for for better performance on web3 operations. If you'd like to take advantage of this performance boost, you'd have to enable app bound domains. To do that, add the following to your Info.plist
and rebuild your app:
01<key>WKAppBoundDomains</key>
02<array>
03 <string>https://auth.magic.link</string>
04</array>
#Constructor
#Magic()
Parameter | Type | Definition |
| String | Your publishable API Key retrieved from the Magic Dashboard. |
|
| (
(
|
|
| Customize the language of Magic's modal, email and confirmation screen. See Localization for more. |
#Initialization
In AppDelegate
01import MagicSDK
02import UIKit
03
04@UIApplicationMain
05func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
06
07 // assign the newly created Magic instance to shared property
08 // Test key defaults to "goerli", live key defaults to "mainnet"
09 Magic.shared = Magic(apiKey: "PUBLISHABLE_API_KEY")
10 // Construct with an API key and options:
11 Magic.shared = Magic(apiKey: "PUBLISHABLE_API_KEY", ethNetwork: .goerli)
12 // Construct with an API key and custom node options:
13 let customNode = CustomNodeConfiguration(rpcUrl: "https://polgyon-rpc.com", chainId: 137)
14 Magic.shared = Magic(apiKey: "PUBLISHABLE_API_KEY", customNode: customNode)
15 // Construct with an API key and custom locale
16 Magic.shared = Magic(apiKey: "PUBLISHABLE_API_KEY", locale: "es")
17
18 return true
19}
#Auth Module
The Auth Module and its members are accessible on the Magic SDK instance by the auth
property.
01import MagicSDK
02
03let magic = Magic.shared
04
05magic.auth;
06magic.auth.loginWithSMS;
07magic.auth.loginWithEmailOTP;
#loginWithSMS
Authenticate a user passwordlessly using a one-time code sent to the specified phone number.
List of Currently Blocked Country Codes
#Arguments
configuration
(LoginWithSMSConfiguration):phoneNumber
(string): The user phone number to log in withshowUI
(boolean): Iftrue
, show an out-of-the-box pending UI while the request is in flight
#Returns
Promise<string | null>
: The promise resolves upon authentication request success and rejects with a specific error code if the request fails. The resolved value is a Decentralized ID token with a default 15-minute lifespan.
#Example
Closure
01import MagicSDK
02
03class LoginViewController: UIViewController {
04
05 @IBOutlet weak var phoneNumberInput: UITextField!
06 let magic = Magic.shared
07
08 @IBAction func login() {
09 guard let magic = magic else { return }
10 guard let phoneNumber = self.phoneNumberInput.text else { return }
11
12 let configuration = LoginWithSMSConfiguration(phoneNumber: phoneNumber, showUI: true)
13
14 magic.auth.loginWithSMS(configuration, response: { response in
15 guard let token = response.result
16 else { return print("Error:", response.error.debugDescription) }
17 print("Result", token)
18 })
19 }
20}
Promise
01import MagicSDK
02
03class LoginViewController: UIViewController {
04
05 @IBOutlet weak var phoneNumberInput: UITextField!
06 let magic = Magic.shared
07
08 @IBAction func login() {
09 guard let magic = magic else { return }
10
11 let configuration = LoginWithSMSConfiguration(phoneNumber: phoneNumber)
12
13 magic.auth.loginWithSMS(configuration).done({ result in
14 print(result) // DIDToken
15 }).catch({
16 print(error) // handle Error
17 })
18 }
19}
#loginWithEmailOTP
Authenticate a user passwordlessly using an email one-time code sent to the specified user's email address.
#Arguments
configuration
(LoginWithEmailOTPConfiguration):email
(string): The user email to log in with
#Returns
Promise<string | null>
: The promise resolves upon authentication request success and rejects with a specific error code if the request fails. The resolved value is a Decentralized ID token with a default 15-minute lifespan.
#Example
Closure
01import MagicSDK
02
03class LoginViewController: UIViewController {
04
05 @IBOutlet weak var emailInput: UITextField!
06 let magic = Magic.shared
07
08 @IBAction func login() {
09 guard let magic = magic else { return }
10 guard let email = self.emailInput.text else { return }
11
12 let configuration = LoginWithEmailOTPConfiguration(email: email)
13
14 magic.auth.loginWithEmailOTP(configuration, response: { response in
15 guard let token = response.result
16 else { return print("Error:", response.error.debugDescription) }
17 print("Result", token)
18 })
19 }
20}
Promise
01import MagicSDK
02
03class LoginViewController: UIViewController {
04
05 @IBOutlet weak var emailInput: UITextField!
06 let magic = Magic.shared
07
08 @IBAction func login() {
09 guard let magic = magic else { return }
10
11 let configuration = LoginWithEmailOTPConfiguration(email: self.emailInput.text!)
12
13 magic.auth.loginWithEmailOTP(configuration).done({ result in
14 print(result) // DIDToken
15 }).catch({
16 print(error) // handle Error
17 })
18 }
19}
#Wallet Module
The Wallet Module and its members are accessible on the Magic SDK instance by the wallet
property.
01import MagicSDK
02
03let magic = Magic.shared
04
05magic.wallet
06magic.wallet.connectWithUI
07magic.wallet.showUI
08magic.wallet.requestUserInfoWithUI
#connectWithUI
Renders a simple login form UI to collect the user's email address and authenticate them passwordlessly using a one-time passcode (OTP) sent to their email address they input.
#Arguments
- None
#Returns
- A
promiEvent
which returns anString[]
when resolved: An array of user accounts that are connected, with the first element being the current public address of the user. You can read more on PromiEvents here.
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 magic.wallet.connectWithUI(response: { response in
12 guard let result = response.result
13 else { return print("Error:", response.error.debugDescription) }
14 print("Result", result)
15 })
16 }
17}
#showUI
Displays the fully navigable wallet to the user that adheres to the toggled configurations on your developer dashboard’s Widget UI tab. This is only supported for users who login with email or Google and not third party wallets such as metamask. User must be signed in for this method to return or else it will throw an error.
#Arguments
- None
#Returns
Promise
which resolves when the user closes the window
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 magic.wallet.showUI(response: { response in
12 guard let result = response.result
13 else { return print("Error:", response.error.debugDescription) }
14 print("Result", result)
15 })
16 }
17}
#requestUserInfoWithUI
Displays the wallet widget within an iframe that prompts the user to consent to sharing information with the requesting dApp with OpenID profile scopes. Currently, the only profile scope that can be requested is a verified email. Collecting a verified email address from third-party wallet users (MetaMask, Coinbase Wallet, etc.) is a premium feature but included in the free trial period (see pricing). User must be signed in for this method to return or else it will throw an error.
#Arguments
configuration
(RequestUserInfoWithUIConfiguration):email
(str): The user email to log in with
#Returns
Promise
which resolves when the user closes the window
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 let config = RequestUserInfoWithUIConfiguration(scope = WalletUserInfoScope(email = "user_email@example.com"))
12
13 magic.wallet.requestUserInfoWithUI(configuration, response: { response in
14 guard let result = response.result
15 else { return print("Error:", response.error.debugDescription) }
16 print("Result", result)
17 })
18 }
19}
#User Module
The User Module and its members are accessible on the Magic SDK instance by the user
property.
01import MagicSDK
02
03let magic = Magic.shared
04
05magic.user
06magic.user.updateEmail
07magic.user.getIdToken
08magic.user.generateIdToken
09magic.user.getInfo
10magic.user.isLoggedIn
11magic.user.logout
12magic.user.showSettings
13magic.user.updatePhoneNumber
14magic.user.recoverAccount
#updateEmail
Initiates the update email flow that allows a user to change to a new email.
#Arguments
configuration
(UpdateEmailConfiguration):email
(string): The user email to update withshowUI
(boolean): Iftrue
, show an out-of-the-box pending UI while the request is in flight
#Returns
Promise<Bool>
: The promise resolves with a true boolean value if update email is successful and rejects with a specific error code if the request fails
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 // Initiates the flow to update a user's current email to a new one.
08 func updateEmail() {
09
10 guard let magic = magic else { return }
11
12 // Assuming user is logged in
13 let configuration = UpdateEmailConfiguration(email: "new_user_email@example.com", showUI: true)
14 magic.user.updateEmail(configuration, response: { response in
15 guard let result = response.result
16 else { return print("Error:", response.error.debugDescription) }
17 print("Result", result)
18 })
19 }
20}
#getIdToken
Generates a Decentralized Id Token which acts as a proof of authentication to resource servers.
#Arguments
configuration
(GetIdTokenConfiguration):lifespan
(number): will set the lifespan of the generated token. Defaults to 900s (15 mins).
#Returns
Promise<String>
: Base64-encoded string representation of a JSON tuple representing[proof, claim]
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func getIdToken() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 let configuration = GetIdTokenConfiguration(lifespan: 900)
12
13 magic.user.getIdToken(configuration, response: { response in
14 guard let token = response.result
15 else { return print(response.error.debugDescription) }
16 print(token)
17 })
18 }
19}
#generateIdToken
Generates a Decentralized Id Token with optional serialized data.
#Arguments
configuration
(GenerateIdTokenConfiguration):lifespan
(number): will set the lifespan of the generated token. Defaults to 900s (15 mins).attachment
(str): will set a signature of serialized data in the generated token. Defaults to"none"
.
#Returns
Promise<String>
: Base64-encoded string representation of a JSON tuple representing[proof, claim]
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func generateIdToken() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 let configuration = GenerateIdTokenConfiguration(lifespan: 900, attachment: "none")
12
13 magic.user.generateIdToken(configuration, response: { response in
14 guard let token = response.result
15 else { return print("Error:", response.error.debugDescription) }
16 print("Result", token)
17 })
18 }
19}
#getInfo
Retrieves information for the authenticated user.
#Arguments
- None
#Returns
Promise<UserInfo>
- The issuer, email and cryptographic public address of the authenticated user.issuer
(string): The Decentralized ID of the user. In server-side use-cases, we recommend this value to be used as the user ID in your own tables.email
(string): Email address of the authenticated userphoneNumber
(string): Phone number of the authenticated userpublicAddress
(string): The authenticated user's public address (a.k.a.: public key). Currently, this value is associated with the Ethereum blockchain.isMfaEnabled
(boolean): A boolean indicating if user has multi-factor authentication enabledrecoveryFactors
(RecoveryFactor):value
(string): Recovery value such as phone numbertype
(RecoveryMethodType): The method used for account recovery
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func getInfo() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 magic.user.getInfo(response: { response in
12 guard let metadata = response.result
13 else { return print("Error:", response.error.debugDescription) }
14 print("Result", metadata)
15 })
16 }
17}
#isLoggedIn
Checks if a user is currently logged in to the Magic SDK.
#Arguments
- None
#Returns
Promise<Bool>
: A boolean value indicating if a user is logged in
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func isLoggedIn() {
08 guard let magic = magic else { return }
09
10 magic.user.isLoggedIn(response: { response in
11 guard let result = response.result
12 else { return print("Error:", response.error.debugDescription) }
13 print("Result", result)
14 })
15 }
16}
#logout
Logs out the currently authenticated Magic user.
#Arguments
- None
#Returns
Promise<Bool>
: A boolean value indicating if a user has been logged out
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 magic.user.logout(response: { response in
12 guard let result = response.result
13 else { return print("Error:", response.error.debugDescription) }
14 print("Result", result)
15 })
16 }
17}
#showSettings
Displays an iframe with the current user’s settings. Allows for users to update their email address, enable multi-factor authentication, and add a recovery factor.
Only available with Dedicated Wallet. Access to MFA and account recovery require paid add-ons.
#Arguments
- None
#Returns
Promise
which resolves when the user closes the window
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 magic.user.showSettings(response: { response in
12 guard let result = response.result
13 else { return print("Error:", response.error.debugDescription) }
14 print("Result", result)
15 })
16 }
17}
#updatePhoneNumber
Initiates the update phone number flow that allows a user to change their phone number.
#Arguments
configuration
:phoneNumber
(str): The user phone number to update with
#Returns
PromiEvent<boolean>
: The promise resolves with a true boolean value if update email is successful and rejects with a specific error code if the request fails
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 let configuration = (phoneNumber: phoneNumber)
12 magic.user.updatePhoneNumber(configuration, response: { response in
13 guard let result = response.result
14 else { return print("Error:", response.error.debugDescription) }
15 print("Result", result)
16 })
17 }
18}
#recoverAccount
Initiates the account recovery flow that allows a user to recover their account using their email address.
#Arguments
configuration
(RecoverAccountConfiguration):email
(str): The user email address to recover account with
#Returns
PromiEvent<boolean>
: The promise resolves with a true boolean value if the account recovery is successful and rejects with a specific error code if the request fails
#Example
01import MagicSDK
02
03class MagicViewController: UIViewController {
04
05 let magic = Magic.shared
06
07 func logout() {
08 guard let magic = magic else { return }
09
10 // Assuming user is logged in
11 let configuration = RecoverAccountConfiguration(email: "recovery_email@example.com")
12 magic.user.recoverAccount(configuration, response: { response in
13 guard let result = response.result
14 else { return print("Error:", response.error.debugDescription) }
15 print("Result", result)
16 })
17 }
18}
#OpenID Module
This module requires an enterprise agreement. For more details click here.
The OpenID Module and it's members are accessible on the Magic SDK instance by the openid
property.
To use the OpenID Module in your application, install MagicExt-OIDC
along with magic-ios
.
01# Cocoapods, in Podfile
02pod 'MagicSDK'
03pod 'MagicExt-OIDC'
04
05# SPM
06Add magic-ios-ext
07Add magic-ios
08
09magic.openid;
10magic.openid.loginWithOIDC;
#loginWithOIDC
Authenticate users via your preferred OIDC client.
Only available with Dedicated Wallet.
#Arguments
jwt
(String): The OIDC token from your identity providerproviderId
(String): An alphanumeric ID provided by Magic after successful configuration of your identity provider
#Returns
PromiEvent<string | null>
: The promise resolves upon authentication request success and rejects with a specific error code if the request fails. The resolved value is a Decentralized ID token with a default 15-minute lifespan.
#Example
01import MagicSDK
02import MagicExt_OIDC
03
04magic = Magic(apiKey: '<your_magic_api_key>')
05
06// MARK: - Openid Login
07func handleOpenIdLogin() {
08 guard let magic = magic else { return }
09
10 let config = OpenIdConfiguration(jwt: jwt, providerId: providerId)
11 magic.openid.loginWithOIDC(config, response: {res in
12 if (res.status.isSuccess) {
13 print(res.result ?? "nil")
14 }
15 })
16}
#Error Handling
There are three types of error class to be aware of when working with Magic's iOS SDK:
#Provider
01public enum ProviderError: Swift.Error {
02 /// The provider is not configured with an authDelegate
03 case encodingFailed(Swift.Error?)
04 /// Decoding the JSON-RPC request failed
05 case decodingFailed(json: String)
06 /// Convert string failed
07 case invalidJsonResponse(json: String)
08 /// Missing callback
09 case missingPayloadCallback(json: String)
10}
#Network
01public enum Error: Swift.Error {
02 /// The response did not include expected results
03 case unexpectedResponse(Swift.Error?)
04 /// The server returned an unexpected response code
05 case invalidResponseCode
06}
#Events
01enum Error: Swift.Error{
02 case eventCallbackMissing
03}