If your app previously used Privy’s Swift 1.Y.Z
SDK, follow the migration guide below to upgrade to 2.0
.
Privy’s 2.Y.Z Swift SDK is Swift 6 compliant and adhere’s to the new strict concurrency standards. We’ve taken this opportunity to also introduce some major API changes, which are outlined below in logical sections.
Previously, apps were only required to pass in an appId
when initializing the Privy SDK. Now, appClientId
is required too. You can retrieve more information on how to retrieve your appClientId here.
It’s important to use a single instance of Privy across the lifetime of your application. Calling PrivySdk.initialize multiple times will result in a fatal error.
When the Privy SDK is first initialized, the user’s authentication state will be set to notReady
until Privy finishes initialization. We’ve added an async privy.awaitReady()
function that allows you to await initialization completion. During this time, we suggest you show a loading state to your user.
Calling PrivySDK functions before calling privy.awaitReady()
might result in unexpected
functionality.
Here’s an example with some pseudocode:
The AuthState
represents the authentication state of your user.
The current auth state can be accessed any time via privy.authState
.
Auth state updates are exposed via privy.authStateStream
, which is an AsyncStream.
After authenticating a user via any login method, you will receive the PrivyUser
object. The PrivyUser
represents an authenticated user. All user specific actions, such as creating a wallet or retrieving the user’s access token, are accessed via the PrivyUser
.
You may retrieve the PrivyUser
anytime by calling privy.user
. If this value is non-null, there is an authenticated user. If the value is null, there is no authenticated user.
The PrivyUser
can also be retrieved via the associated type of the “authenticated” auth state:
Use the PrivyUser
object to:
We’ve significantly enhanced our error handling. When an SDK function throws an error, it will be a PrivyError
, which contains an errorCode
and a localizedDescription
.
The AuthSession
is no longer exposed. Values previously available in AuthSession are now available through different methods:
PrivyUser
: can be accessed via privy.user
as described above.accessToken
: can be accessed via privy.user.getAccessToken()
. This method will return the user’s access token, refreshing the session if needed.To refresh / update a PrivyUser
, you’d previously call privy.refreshSession
. Now, trigger the refresh via the PrivyUser
, specifically, privyUser.refresh
.
To logout an authenticated user, call await privyUser.logout()
instead of privy.logout()
. Once calling logout, the PrivyUser
instance is no longer valid.
LinkedAccount
and its associated types are no longer Codable
, Hashable
, Identifiable
or Equatable
.LinkedAccount.embeddedWallet
is now split into chain specific values - LinkedAccount.embeddedEthereumWallet
and LinkedAccount.embeddedSolanaWallet
chainId
property on the embedded wallet linked accounts is removed.firstVerifiedAt
and latestVerifiedAt
fields are now optional values.firstVerifiedAt
, latestVerifiedAt
, and createdAt
fields now have type Date
instead of TimeInterval
or Int
verifiedAt
fields now replaced with firstVerifiedAt
and latestVerifiedAt
LoginMethod
is no longer Equatable
OtpFlowState
enum is no longer exposed. You should manually handle state management based on function results. For example, if LoginWithSms.loginWithCode
throws an error, you can catch the error and update your UI accordingly.LoginWithSms.sendCode
now throws an error if sending code is unsuccessful, instead of returning falseLoginWithSms.loginWithCode
now returns PrivyUser
LoginWithSms.loginWithCode
now requires phone number to be passed in as a parameter (previously was optional)OtpFlowState
enum is no longer exposed. You should manually handle state management based on function results. For example, if LoginWithEmail.loginWithCode
throws an error, you can catch the error and update your UI accordingly.LoginWithEmail.sendCode
now throws an error if sending code is unsuccessful, instead of returning falseLoginWithEmail.linkWithCode
no longer returns anything, and throws an error if linking failsLoginWithEmail.loginWithCode
now returns PrivyUser
LoginWithEmail.loginWithCode
now requires email to be passed in (no longer optional)LoginWithCustomAccessToken.loginWithCustomAccessToken
now returns PrivyUser
TokenProvider
through the PrivyLoginWithCustomAuthConfig
field in the PrivyConfig
object. This allows Privy to access your user’s access token at initialization while attempting to restore the Privy user’s session.SiweFlowState
enum is no longer exposed. You should manually handle state management based on function results. For example, if LoginWithSiwe.loginWithSiwe
throws an error, you can catch the error and update your UI accordingly.LoginWithSiwe.loginWithSiwe
now returns PrivyUser
LoginWithSiwe.loginWithSiwe
now requires message and params to be passed in (no longer optional)LoginWithSiwe.linkWithSiwe
no long returns anything, and throws an error if linking failsLoginWithSiwe.linkWithSiwe
now requires message and params to be passed in (no longer optional)PrivyUser
Previously, all embedded wallet APIs were accessible directly from the privy.embeddedWallet
object, which is no longer available.
All embedded wallet APIs are now available via the PrivyUser
instead. This is because all embedded wallet actions require an authenticated user, so adding the methods inside the authenticated PrivyUser
was the most logical.
As an example, when creating an Ethereum wallet:
In SDK 1.Y.Z, you had to ensure wallets were connected prior to accessing them by calling privy.connectWallet()
. This method is now removed as we handle connected state internally! You may access the user’s embedded wallets at anytime, without ensuring “wallet connected” state.
Because you no longer need to manage wallet state, EmbeddedWalletState
has been removed.
Now, all embedded wallet APIs are chain specific and available via the PrivyUser
.
Ethereum:
Solana:
Ethereum:
Solana:
Instead of grabbing the wallet’s provider via try privy.embeddedWallet.getEthereumProvider(for: wallet.address)
, the provider is now available directly on the wallet instance. For example:
Ethereum:
Further, switching and retrieving the EVM chain is now an async operation:
Solana:
When utilizing the EmbeddedEthereumWalletProvider
, you may specify the EVM Chain by calling provider.switchChain
. This was previously named provider.configure
.
If your app previously used Privy’s Swift 1.Y.Z
SDK, follow the migration guide below to upgrade to 2.0
.
Privy’s 2.Y.Z Swift SDK is Swift 6 compliant and adhere’s to the new strict concurrency standards. We’ve taken this opportunity to also introduce some major API changes, which are outlined below in logical sections.
Previously, apps were only required to pass in an appId
when initializing the Privy SDK. Now, appClientId
is required too. You can retrieve more information on how to retrieve your appClientId here.
It’s important to use a single instance of Privy across the lifetime of your application. Calling PrivySdk.initialize multiple times will result in a fatal error.
When the Privy SDK is first initialized, the user’s authentication state will be set to notReady
until Privy finishes initialization. We’ve added an async privy.awaitReady()
function that allows you to await initialization completion. During this time, we suggest you show a loading state to your user.
Calling PrivySDK functions before calling privy.awaitReady()
might result in unexpected
functionality.
Here’s an example with some pseudocode:
The AuthState
represents the authentication state of your user.
The current auth state can be accessed any time via privy.authState
.
Auth state updates are exposed via privy.authStateStream
, which is an AsyncStream.
After authenticating a user via any login method, you will receive the PrivyUser
object. The PrivyUser
represents an authenticated user. All user specific actions, such as creating a wallet or retrieving the user’s access token, are accessed via the PrivyUser
.
You may retrieve the PrivyUser
anytime by calling privy.user
. If this value is non-null, there is an authenticated user. If the value is null, there is no authenticated user.
The PrivyUser
can also be retrieved via the associated type of the “authenticated” auth state:
Use the PrivyUser
object to:
We’ve significantly enhanced our error handling. When an SDK function throws an error, it will be a PrivyError
, which contains an errorCode
and a localizedDescription
.
The AuthSession
is no longer exposed. Values previously available in AuthSession are now available through different methods:
PrivyUser
: can be accessed via privy.user
as described above.accessToken
: can be accessed via privy.user.getAccessToken()
. This method will return the user’s access token, refreshing the session if needed.To refresh / update a PrivyUser
, you’d previously call privy.refreshSession
. Now, trigger the refresh via the PrivyUser
, specifically, privyUser.refresh
.
To logout an authenticated user, call await privyUser.logout()
instead of privy.logout()
. Once calling logout, the PrivyUser
instance is no longer valid.
LinkedAccount
and its associated types are no longer Codable
, Hashable
, Identifiable
or Equatable
.LinkedAccount.embeddedWallet
is now split into chain specific values - LinkedAccount.embeddedEthereumWallet
and LinkedAccount.embeddedSolanaWallet
chainId
property on the embedded wallet linked accounts is removed.firstVerifiedAt
and latestVerifiedAt
fields are now optional values.firstVerifiedAt
, latestVerifiedAt
, and createdAt
fields now have type Date
instead of TimeInterval
or Int
verifiedAt
fields now replaced with firstVerifiedAt
and latestVerifiedAt
LoginMethod
is no longer Equatable
OtpFlowState
enum is no longer exposed. You should manually handle state management based on function results. For example, if LoginWithSms.loginWithCode
throws an error, you can catch the error and update your UI accordingly.LoginWithSms.sendCode
now throws an error if sending code is unsuccessful, instead of returning falseLoginWithSms.loginWithCode
now returns PrivyUser
LoginWithSms.loginWithCode
now requires phone number to be passed in as a parameter (previously was optional)OtpFlowState
enum is no longer exposed. You should manually handle state management based on function results. For example, if LoginWithEmail.loginWithCode
throws an error, you can catch the error and update your UI accordingly.LoginWithEmail.sendCode
now throws an error if sending code is unsuccessful, instead of returning falseLoginWithEmail.linkWithCode
no longer returns anything, and throws an error if linking failsLoginWithEmail.loginWithCode
now returns PrivyUser
LoginWithEmail.loginWithCode
now requires email to be passed in (no longer optional)LoginWithCustomAccessToken.loginWithCustomAccessToken
now returns PrivyUser
TokenProvider
through the PrivyLoginWithCustomAuthConfig
field in the PrivyConfig
object. This allows Privy to access your user’s access token at initialization while attempting to restore the Privy user’s session.SiweFlowState
enum is no longer exposed. You should manually handle state management based on function results. For example, if LoginWithSiwe.loginWithSiwe
throws an error, you can catch the error and update your UI accordingly.LoginWithSiwe.loginWithSiwe
now returns PrivyUser
LoginWithSiwe.loginWithSiwe
now requires message and params to be passed in (no longer optional)LoginWithSiwe.linkWithSiwe
no long returns anything, and throws an error if linking failsLoginWithSiwe.linkWithSiwe
now requires message and params to be passed in (no longer optional)PrivyUser
Previously, all embedded wallet APIs were accessible directly from the privy.embeddedWallet
object, which is no longer available.
All embedded wallet APIs are now available via the PrivyUser
instead. This is because all embedded wallet actions require an authenticated user, so adding the methods inside the authenticated PrivyUser
was the most logical.
As an example, when creating an Ethereum wallet:
In SDK 1.Y.Z, you had to ensure wallets were connected prior to accessing them by calling privy.connectWallet()
. This method is now removed as we handle connected state internally! You may access the user’s embedded wallets at anytime, without ensuring “wallet connected” state.
Because you no longer need to manage wallet state, EmbeddedWalletState
has been removed.
Now, all embedded wallet APIs are chain specific and available via the PrivyUser
.
Ethereum:
Solana:
Ethereum:
Solana:
Instead of grabbing the wallet’s provider via try privy.embeddedWallet.getEthereumProvider(for: wallet.address)
, the provider is now available directly on the wallet instance. For example:
Ethereum:
Further, switching and retrieving the EVM chain is now an async operation:
Solana:
When utilizing the EmbeddedEthereumWalletProvider
, you may specify the EVM Chain by calling provider.switchChain
. This was previously named provider.configure
.