Logto is an Auth0 alternative designed for modern apps and SaaS products. It offers both Cloud and Open-source services to help you quickly launch your identity and management (IAM) system. Enjoy authentication, authorization, and multi-tenant management all in one.
We recommend starting with a free development tenant on Logto Cloud. This allows you to explore all the features easily.
In this article, we will go through the steps to quickly build the Okta enterprise SSO sign-in experience (user authentication) with iOS (Swift) and Logto.
Prerequisites
- A running Logto instance. Check out the introduction page to get started.
- Basic knowledge of iOS (Swift).
- A usable Okta enterprise SSO account.
Create an application in Logto
Logto is based on OpenID Connect (OIDC) authentication and OAuth 2.0 authorization. It supports federated identity management across multiple applications, commonly called Single Sign-On (SSO).
To create your Native app application, simply follow these steps:
- Open the Logto Console. In the "Get started" section, click the "View all" link to open the application frameworks list. Alternatively, you can navigate to Logto Console > Applications, and click the "Create application" button.
- In the opening modal, click the "Native app" section or filter all the available "Native app" frameworks using the quick filter checkboxes on the left. Click the "iOS (Swift)" framework card to start creating your application.
- Enter the application name, e.g., "Bookstore," and click "Create application".
🎉 Ta-da! You just created your first application in Logto. You'll see a congrats page which includes a detailed integration guide. Follow the guide to see what the experience will be in your application.
Integrate iOS (Swift) with Logto
Add Logto SDK as a dependency
The minimum supported iOS version of Logto Swift SDK is iOS 13.
Logto Swift SDK comes in two major versions:
- v1: Opens the sign-in experience in an embedded WebView, which is required by the native social plugin targets, but does not support passkey sign-in (WebView does not support WebAuthn, the underlying standard of passkeys).
- v2 (beta): Opens the sign-in experience in
ASWebAuthenticationSession(the system browser), which unlocks passkey sign-in and shares the browser session. Note that v2 removes the native social plugin targets; social connectors still work through the browser. If you depend on the native WeChat or Alipay SDK handoff, stay on v1.
This guide covers both versions. Choose your version in the tabs below, and the choice will be kept in sync throughout this guide.
Use the following URL to add Logto SDK as a dependency in Swift Package Manager.
https://github.com/logto-io/swift.git
Since Xcode 11, you can directly import a Swift package w/o any additional tool.
When Xcode asks for the package version, choose the version you want to integrate:
- v2 (beta)
- v1
v2 is released as 2.0.0-beta.x prereleases until GA. Use 2.0.0-beta.1 or the latest 2.0.0-beta.x prerelease as the version. During beta, we recommend selecting the prerelease explicitly instead of relying on a normal version range to pick it automatically.
If you use Package.swift directly:
.package(url: "https://github.com/logto-io/swift.git", exact: "2.0.0-beta.1")
Use the latest v1 release as the stable line. The latest v1 version is 1.2.0.
If you use Package.swift directly:
.package(url: "https://github.com/logto-io/swift.git", from: "1.2.0")
We do not support Carthage and CocoaPods at the time due to some technical issues.
Carthage
Carthage needs a xcodeproj file to build. We will try to find a workaround later.
CocoaPods
CocoaPods does not support local dependency and monorepo, thus it's hard to create a .podspec for this repo.
Init LogtoClient
Initialize the client by creating a LogtoClient instance with a LogtoConfig object.
import Logto
import LogtoClient
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // E.g. http://localhost:3001
appId: "<your-app-id>"
)
let client = LogtoClient(useConfig: config)
By default, we store credentials like ID Token and Refresh Token in the Keychain. Thus the user doesn't need to sign in again when he returns.
To turn off this behavior, set usingPersistStorage to false:
let config = try? LogtoConfig(
// ...
usingPersistStorage: false
)
Sign in
Before we dive into the details, here's a quick overview of the end-user experience. The sign-in process can be simplified as follows:
- Your app invokes the sign-in method.
- The user is redirected to the Logto sign-in page. For native apps, the system browser is opened.
- The user signs in and is redirected back to your app (configured as the redirect URI).
Regarding redirect-based sign-in
- This authentication process follows the OpenID Connect (OIDC) protocol, and Logto enforces strict security measures to protect user sign-in.
- If you have multiple apps, you can use the same identity provider (Logto). Once the user signs in to one app, Logto will automatically complete the sign-in process when the user accesses another app.
To learn more about the rationale and benefits of redirect-based sign-in, see Logto sign-in experience explained.
Configure redirect URI
- v2 (beta)
- v1
Let's switch to the Application details page of Logto Console. Add a Redirect URI io.logto.app://callback and click "Save changes".

In v2, the sign-in experience opens in ASWebAuthenticationSession (the system browser), and the redirect is routed back to your app through OS-level callback matching. For a custom scheme redirect URI such as io.logto.app://callback, register only the scheme part (io.logto.app) in your app's Info.plist, then add the full redirect URI to your Logto application's Redirect URIs.
In Xcode, open your app target, select Info, expand URL Types, and add one entry with io.logto.app in URL Schemes. If you edit Info.plist directly, add:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>io.logto.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>io.logto.app</string>
</array>
</dict>
</array>
For the browser flow in v2, you do not need to call LogtoClient.handle(url:); that plugin handoff API was removed with the embedded WebView flow.
Use Universal Links instead of a custom scheme?
You can also use an HTTPS redirect URI such as https://example.com/callback:
- Add the Associated Domains capability to your app.
- Configure
webcredentials:example.comsoASWebAuthenticationSessioncan match HTTPS callbacks on iOS 17.4 and newer. - If the same URL should also open your app as a Universal Link outside the authentication session, configure
applinks:example.comand host a validapple-app-site-associationfile for the domain and path. - Add the HTTPS URI to your Logto application's Redirect URIs.
- Pass the same URI to
signInWithBrowser.
On iOS 17.4 and newer, the SDK uses ASWebAuthenticationSession's HTTPS callback matching API so HTTPS redirects can automatically complete and dismiss the session. On older iOS versions, the authorization request can still use the HTTPS redirect URI, but the session may not close automatically unless your app handles the Universal Link callback itself. Keep a custom scheme redirect as a compatibility option if you need automatic completion on older iOS versions.
Let's switch to the Application details page of Logto Console. Add a Redirect URI io.logto://callback and click "Save changes".

The Redirect URI in iOS SDK is only for internal use. There's NO NEED to add a Custom URL Scheme until a connector asks.
Sign-in and sign-out
Before calling .signInWithBrowser(redirectUri:), make sure you have correctly configured Redirect URI
in Admin Console.
- v2 (beta)
- v1
In v2, client.signOut(postLogoutRedirectUri:) performs a complete sign-out: it clears the local credentials, revokes the refresh token, and ends the Logto session by opening the end session endpoint in the system browser. The browser then navigates back to your app through the post sign-out redirect URI. Before using it, switch to the application details page of Logto Console, add the post sign-out redirect URI io.logto.app://signed-out and click "Save changes". The post sign-out redirect URI can use the same custom scheme you registered for sign-in.
For example, in a SwiftUI app:
struct ContentView: View {
@State var isAuthenticated: Bool
private let redirectUri = "io.logto.app://callback"
private let postLogoutRedirectUri = "io.logto.app://signed-out"
init() {
isAuthenticated = client.isAuthenticated
}
var body: some View {
VStack {
if isAuthenticated {
Button("Sign Out") {
Task { [self] in
let error = await client.signOut(postLogoutRedirectUri: postLogoutRedirectUri)
if let error = error {
print(error)
return
}
isAuthenticated = false
}
}
} else {
Button("Sign In") {
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: redirectUri)
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {
// error occurred during sign in
} catch {
// other errors
}
}
}
}
}
}
}
- You can also call
client.signOut()without a post sign-out redirect URI. No Console configuration is needed in this case: the browser shows the Logto sign-out page, and the user returns to the app by dismissing it manually. - If no UI context is available, you can call
client.clearCredentials()to clear the local credentials and revoke the refresh token. Note that this keeps the Logto session in the browser, so the nextsignInWithBrowsermay silently sign the user back in through that session.
You can use client.signInWithBrowser(redirectUri:) to sign in the user and client.signOut() to sign out the user.
For example, in a SwiftUI app:
struct ContentView: View {
@State var isAuthenticated: Bool
init() {
isAuthenticated = client.isAuthenticated
}
var body: some View {
VStack {
if isAuthenticated {
Button("Sign Out") {
Task { [self] in
await client.signOut()
isAuthenticated = false
}
}
} else {
Button("Sign In") {
Task { [self] in
do {
try await client.signInWithBrowser(redirectUri: "io.logto://callback")
isAuthenticated = true
} catch let error as LogtoClientErrors.SignIn {
// error occurred during sign in
} catch {
// other errors
}
}
}
}
}
}
}
Checkpoint: Test your application
Now, you can test your application:
- Run your application, you will see the sign-in button.
- Click the sign-in button, the SDK will init the sign-in process and redirect you to the Logto sign-in page.
- After you signed in, you will be redirected back to your application and see the sign-out button.
- Click the sign-out button to clear token storage and sign out.
Add Okta enterprise SSO connector
To simplify access management and gain enterprise-level safeguards for your big clients, connect with iOS (Swift) as a federated identity provider. The Logto enterprise SSO connector helps you establish this connection in minutes by allowing several parameter inputs.
To add an enterprise SSO connector, simply follow these steps:
- Navigate to Logto console > Enterprise SSO.
- Click "Add enterprise connector" button and choose your SSO provider type. Choose from prebuilt connectors for Microsoft Entra ID (Azure AD), Google Workspace, and Okta, or create a custom SSO connection using the standard OpenID Connect (OIDC) or SAML protocol.
- Provide a unique name (e.g., SSO sign-in for Acme Company).
- Configure the connection with your IdP in the "Connection" tab. Check the guides above for each connector types.
- Customize the SSO experience and enterprise’s email domain in the "Experience" tab. Users sign in with the SSO-enabled email domain will be redirected to SSO authentication.
- Save changes.
Set up OIDC application on Okta admin portal
Step 1: Create an OIDC application on Okta admin portal
- Visit the Okta admin portal and sign in as an administrator.
- Navigate to the
Applications/Applicationspage using the side menu. - Click the
Create App Integrationbutton to create a new OIDC application. - Select the
OIDC - OpenID Connectoption as theSign-in method. - Select the
Web Applicationoption as theApplication type.
Click the Next button to continue.
Step 2: Configure the application settings
- Provide an
App integration name. It will be used as the identifier of your OIDC application. - Add a new
Sign-in redirect URIsusing the Logto SSO connector's callback URL.
This is the URI that the Okta will redirect the user's browser after successful authentication. After a user successfully authenticates with the IdP, the IdP redirects the user's browser back to this designated URI along with an authorization code. Logto will complete the authentication process based on the authorization code received from this URI.
- Assign users to the application.
Based on the Assignments settings, you can choose to assign the application to all users or specific users/groups.
Click the Save button to save the application settings.
Step 3: Set up Logto connector with the client credentials
After successfully creating the OIDC application, you will be redirected to the application details page.
Copy the client ID and client secret and fill in the corresponding fields on the Logto SSO connector Connection tab.
Use your Okta domain as the issuer. Example: https://dev-12345678.okta.com. Once you have filled in all the fields, click the Save button to save the connector settings.
If the issuer link you provided is valid, you will see a parsed full list of Okta IdP configurations shown below the issuer field.
Step 4: Additional scopes (Optional)
Scopes define the permissions your app requests from users and control which data your app can access from their Okta accounts. Requesting additional Okta permissions requires configuration on both sides:
In Okta admin console:
- Navigate to Applications > Applications and select your OIDC application.
- Go to the Assignments tab to ensure your app has access to the required users and groups.
- For custom scopes, navigate to Security > API > Authorization Servers and select your authorization server.
- Add custom scopes if needed:
- Click Scopes and then Add Scope
- Define scope names like
okta.users.readorokta.groups.readfor accessing Okta APIs - Configure consent requirements for each scope
For a complete list of available scopes and their descriptions, please refer to the Okta OIDC documentation.
In Logto Okta connector:
- Logto automatically includes
openid,profile, andemailscopes to retrieve basic user identity information. You can leave theScopesfield blank if you only need basic user information. - Add
offline_accessto theScopesfield if you plan to store tokens for persistent API access. This scope enables refresh tokens for long-lived API access. - Add additional scopes (separated by spaces) in the
Scopesfield to request more data from Okta. For example:okta.users.read okta.groups.read
If your app requests these scopes to access Okta APIs and perform actions, make sure to enable Store tokens for persistent API access in Logto Okta connector. See the next section for details.
Step 5: Store tokens to access Okta APIs (Optional)
If you want to access Okta scopes and perform actions with user authorization, Logto needs to get specific scopes and store tokens.
- Add the required scopes in your Okta developer console API permissions configuration and Logto Okta connector.
- Enable Store tokens for persistent API access in Logto Okta connector. Logto will securely store Okta access and refresh tokens in the Secret Vault.
- To ensure refresh tokens are returned, add the
offline_accessscope to your Okta application permissions and include it in your Logto Okta connector scopes. This scope allows your application to maintain access to resources for extended periods.
Step 6: Set email domains and enable the SSO connector
Provide the email domains of your organization on Logto's connector SSO experience tab. This will enable the SSO connector as an authentication method for those users.
Users with email addresses in the specified domains will be redirected to use your SSO connector as their only authentication method.
For more details about creating OIDC integration with Okta, please check Create OIDC App Integrations.
Save your configuration
Double check you have filled out necessary values in the Logto connector configuration area. Click "Save and Done" (or "Save changes") and the Okta enterprise SSO connector should be available now.
Enable Okta enterprise SSO connector in Sign-in Experience
You don’t need to configure enterprise connectors individually, Logto simplifies SSO integration into your applications with just one click.
- Navigate to: Console > Sign-in & account > Sign-up and sign-in.
- Enable the "Enterprise SSO" toggle.
- Save changes.
Once enabled, a "Single Sign-On" button will appear on your sign-in page. Enterprise users with SSO-enabled email domains can access your services using their enterprise identity providers (IdPs).
To learn more about the SSO user experience, including SP-initiated SSO and IdP-initiated SSO, refer to User flows: Enterprise SSO.
Testing and Validation
Return to your iOS (Swift) app. You should now be able to sign in with Okta enterprise SSO. Enjoy!
Further readings
End-user flows: Logto provides a out-of-the-box authentication flows including MFA and enterprise SSO, along with powerful APIs for flexible implementation of account settings, security verification, and multi-tenant experience.
Authorization: Authorization defines the actions a user can do or resources they can access after being authenticated. Explore how to protect your API for native and single-page applications and implement Role-based Access Control (RBAC).
Organizations: Particularly effective in multi-tenant SaaS and B2B apps, the organization feature enable tenant creation, member management, organization-level RBAC, and just-in-time-provisioning.
Customer IAM series Our serial blog posts about Customer (or Consumer) Identity and Access Management, from 101 to advanced topics and beyond.