Using custom authentication in iOS SDK
Custom authentication lets you use your own identity provider to sign users in directly. For example, you can use your own Google Client ID when authenticating with Google.
With MFA disabled, custom authentication makes the wallet infrastructure invisible to your users, so they don't see any authentication modal or branding.
This is a paid feature and the minimum pricing plan to use this SDK in a production environment is the Growth Plan. You can use this feature in Web3Auth Sapphire Devnet network for free.
Create a connection
Create a connection from the Authentication tab of your project in the Embedded Wallets dashboard.
Provide your connection details in the Embedded Wallets dashboard to generate an authConnectionId.
The SDK uses this ID to identify the connection during initialization. You can configure multiple
connections for the same project and update them anytime.
See authentication provider setup for available connection configurations.
Configuration
To use custom authentication with supported social providers or login providers like Auth0, AWS
Cognito, Firebase, or your own custom JWT, add the configuration using the authConnectionConfig
parameter during initialization.
The authConnectionConfig parameter is an array of AuthConnectionConfig instances, each defining
a specific authentication connection.
Parameters
After creating the auth connection from the Web3Auth Dashboard, you can use the following parameters in the AuthConnectionConfig.
- Table
- Struct
| Parameter | Description |
|---|---|
authConnectionId | Name of the auth connection registered in the Embedded Wallets dashboard. Required. String. |
authConnection | Sign-in type for this connection. .GOOGLE triggers a Google sign-in flow; .CUSTOM expects your own JWT token with no sign-in flow. Required. AuthConnection. |
clientId | Client ID from your sign-in provider (for example, Google Client ID), or your Embedded Wallets client ID when using .CUSTOM. Required. String. |
name? | Display name for the auth connection. If nil, the default name is used. String. |
description? | Description for the sign-in button. If provided, the button renders at full width; otherwise it renders as an icon button. String. |
groupedAuthConnectionId? | JWT token field that maps to a grouped auth connection ID. Must match the JWT auth connection ID configured in the dashboard. String. |
logoHover? | Logo shown on mouse hover. String. |
logoLight? | Light logo for dark backgrounds. String. |
logoDark? | Dark logo for light backgrounds. String. |
mainOption? | Show the sign-in button on the main list. Default is false. Bool. |
showOnModal? | Show the sign-in button on the modal. Default is true. Bool. |
showOnDesktop? | Show the sign-in button on desktop. Default is true. Bool. |
showOnMobile? | Show the sign-in button on mobile. Default is true. Bool. |
public struct AuthConnectionConfig: Codable {
let authConnectionId: String
let authConnection: AuthConnection
let name: String?
let description: String?
let clientId: String
let groupedAuthConnectionId: String?
let logoHover: String?
let logoLight: String?
let logoDark: String?
let mainOption: Bool?
let showOnModal: Bool?
let showOnDesktop: Bool?
let showOnMobile: Bool?
let jwtParameters: ExtraLoginOptions?
let isDefault: Bool?
}
public enum AuthConnection: String, Codable {
case GOOGLE = "google"
case FACEBOOK = "facebook"
case REDDIT = "reddit"
case DISCORD = "discord"
case TWITCH = "twitch"
case APPLE = "apple"
case LINE = "line"
case GITHUB = "github"
case KAKAO = "kakao"
case LINKEDIN = "linkedin"
case TWITTER = "twitter"
case WEIBO = "weibo"
case WECHAT = "wechat"
case EMAIL_PASSWORDLESS = "email_passwordless"
case CUSTOM = "custom"
case SMS_PASSWORDLESS = "sms_passwordless"
case FARCASTER = "farcaster"
}
Usage
- JWT
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth",
authConnectionConfig: [
AuthConnectionConfig(
authConnectionId: "your-auth-connection-id", // Get it from Web3Auth Dashboard
authConnection: .GOOGLE,
clientId: "YOUR_GOOGLE_CLIENT_ID"
)
]
)
)
let result = try await web3Auth.connectTo(loginParams: LoginParams(authConnection: .GOOGLE))
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth",
authConnectionConfig: [
AuthConnectionConfig(
authConnectionId: "your-auth-connection-id", // Get it from Web3Auth Dashboard
authConnection: .FACEBOOK,
clientId: "YOUR_FACEBOOK_CLIENT_ID"
)
]
)
)
let result = try await web3Auth.connectTo(loginParams: LoginParams(authConnection: .FACEBOOK))
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth",
authConnectionConfig: [
AuthConnectionConfig(
authConnectionId: "your-auth-connection-id", // Get it from Web3Auth Dashboard
authConnection: .CUSTOM,
clientId: "YOUR_WEB3AUTH_CLIENT_ID"
)
]
)
)
let result = try await web3Auth.connectTo(loginParams: LoginParams(authConnection: .CUSTOM))
Configure extra login options
In addition to the auth connection config during initialization, you can pass extra options to the
connectTo function to configure the login flow. ExtraLoginOptions accepts the following parameters.
Parameters
- Table
- Struct
| Parameter | Description |
|---|---|
additionalParams? | Additional parameters in [String: String] format for OAuth sign-in. Use id_token (JWT) to authenticate with the SDK. [String: String]. |
domain? | Custom authentication domain (for example, example.au.auth0.com for Auth0). String. |
client_id? | Client ID from your sign-in provider for custom auth connections. String. |
leeway? | Clock-skew tolerance for JWT expiration, in seconds. Recommended maximum is 120 seconds. Int. |
userIdField? | JWT token field that maps to the user ID. Must match the JWT user ID configured in the dashboard. String. |
isUserIdCaseSensitive? | Whether the user ID field is case-sensitive. Bool. |
display? | OIDC display parameter controlling how the authentication UI renders (for example, page, popup, touch). String. |
prompt? | OIDC prompt parameter shown during authentication (for example, login, consent, none). String. |
max_age? | Maximum time (in seconds) since the last authentication before the user must re-authenticate. String. |
ui_locales? | Space-separated list of language tags, ordered by preference (for example, fr-CA fr en). String. |
id_token_hint? | Previously issued ID token, used as a hint for re-authentication. String. |
id_token? | JWT (ID token) to pass for sign-in. String. |
access_token? | Access token for OAuth flows. String. |
flow_type? | Email passwordless flow type. EmailFlowType (.code or .link). |
acr_values? | Authentication context class reference values requested from the provider. String. |
scope? | Default scope for authentication requests. String. |
audience? | Audience for the access token, presented as the aud claim. String. |
connection? | Name of the connection configured for your dapp. If nil, redirects to the Auth0 sign-in page. String. |
state? | Opaque value used to maintain state between the request and callback, preventing CSRF attacks. String. |
response_type? | Grant type to execute for the authorization server. String. |
nonce? | Random value used to prevent replay attacks in OIDC flows. String. |
redirect_uri? | URL where your custom JWT verifier redirects the browser with the result. For Auth0, must be allowlisted in Allowed Callback URLs in your Auth0 application. |
public struct ExtraLoginOptions: Codable {
let display: String?
let prompt: String?
let max_age: String?
let ui_locales: String?
let id_token_hint: String?
let id_token: String?
var login_hint: String?
let acr_values: String?
let scope: String?
let audience: String?
let connection: String?
let domain: String?
let client_id: String?
let redirect_uri: String?
let leeway: Int?
let userIdField: String?
let isUserIdCaseSensitive: Bool?
let additionalParams: [String: String]?
let access_token: String?
let flow_type: EmailFlowType?
}
public enum EmailFlowType: String, Codable {
case code = "code"
case link = "link"
}
Single auth connection example
- Auth0
- Custom JWT
- Email Passwordless
- SMS Passwordless
Auth0 has a special login flow called the SPA flow. This flow requires a client_id and domain, and
the SDK retrieves the JWT id_token from Auth0 directly. Pass these values in the ExtraLoginOptions
object in the connectTo call.
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth",
authConnectionConfig: [
AuthConnectionConfig(
authConnectionId: "your-auth-connection-id", // Get it from Web3Auth Dashboard
authConnection: .CUSTOM,
clientId: "YOUR_AUTH0_CLIENT_ID"
)
]
)
)
let result = try await web3Auth.connectTo(
loginParams: LoginParams(
authConnection: .CUSTOM,
extraLoginOptions: ExtraLoginOptions(
domain: "https://username.us.auth0.com", // Domain of your Auth0 app
userIdField: "sub" // The field in JWT token which maps to user ID
)
)
)
If you're using another provider like Firebase, AWS Cognito, or your own custom JWT server, pass the
JWT token in the idToken parameter of LoginParams. In Single Factor Auth (SFA) mode, this
enables direct authentication without additional login flows.
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth",
authConnectionConfig: [
AuthConnectionConfig(
authConnectionId: "your-auth-connection-id", // Get it from Web3Auth Dashboard
authConnection: .CUSTOM,
clientId: "YOUR_WEB3AUTH_CLIENT_ID"
)
]
)
)
let result = try await web3Auth.connectTo(
loginParams: LoginParams(
authConnection: .CUSTOM,
authConnectionId: "your-auth-connection-id",
idToken: "your_jwt_token" // Direct SFA authentication
)
)
For Email Passwordless login, pass the email address as the loginHint parameter of LoginParams.
The default flow is code (OTP). To use a magic link flow instead, set flow_type to .link in
extraLoginOptions.
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth"
)
)
let result = try await web3Auth.connectTo(
loginParams: LoginParams(
authConnection: .EMAIL_PASSWORDLESS,
loginHint: "hello@web3auth.io",
extraLoginOptions: ExtraLoginOptions(
flow_type: .code // Use .code for OTP flow or .link for magic link flow
)
)
)
For SMS Passwordless login, pass the phone number as the loginHint parameter of LoginParams.
The phone number must use the format +{country_code}-{phone_number}, for example +91-9911223344.
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth"
)
)
let result = try await web3Auth.connectTo(
loginParams: LoginParams(
authConnection: .SMS_PASSWORDLESS,
loginHint: "+91-9911223344"
)
)
Grouped auth connection example
Grouped auth connections combine multiple login methods so your users get the same address regardless of how they sign in. For example, combine Google and Email Passwordless, or Google and GitHub via Auth0, to resolve to the same address.
import Web3Auth
let web3Auth = try await Web3Auth(
options: Web3AuthOptions(
clientId: "YOUR_WEB3AUTH_CLIENT_ID",
web3AuthNetwork: .SAPPHIRE_MAINNET,
redirectUrl: "com.yourapp.bundleid://auth",
authConnectionConfig: [
AuthConnectionConfig(
authConnectionId: "aggregate-sapphire",
groupedAuthConnectionId: "w3a-google",
authConnection: .GOOGLE,
name: "Aggregate Login",
clientId: "YOUR_GOOGLE_CLIENT_ID"
),
AuthConnectionConfig(
authConnectionId: "aggregate-sapphire",
groupedAuthConnectionId: "w3a-a0-email-passwordless",
authConnection: .CUSTOM,
name: "Aggregate Login",
clientId: "YOUR_AUTH0_CLIENT_ID"
)
]
)
)
func loginWithGoogle() async throws {
let result = try await web3Auth.connectTo(loginParams: LoginParams(authConnection: .GOOGLE))
}
func loginWithGitHub() async throws {
let result = try await web3Auth.connectTo(
loginParams: LoginParams(
authConnection: .CUSTOM,
extraLoginOptions: ExtraLoginOptions(
connection: "github",
domain: "https://web3auth.au.auth0.com",
userIdField: "email",
isUserIdCaseSensitive: false
)
)
)
}