Authentifizierung zu deiner iOS (Swift)-Anwendung hinzufügen
Diese Anleitung geht davon aus, dass du eine Anwendung des Typs "Native app" in der Admin-Konsole erstellt hast.
Installation
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.
Integration
Init LogtoClient
Initialisiere den Client, indem du eine LogtoClient-Instanz mit einem LogtoConfig-Objekt erstellst.
import Logto
import LogtoClient
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Z.B. http://localhost:3001
appId: "<your-app-id>"
)
let client = LogtoClient(useConfig: config)
Standardmäßig speichern wir Anmeldeinformationen wie ID-Token und Auffrischungstoken im Schlüsselbund. Daher muss sich der Benutzer nicht erneut anmelden, wenn er zurückkehrt.
Um dieses Verhalten zu deaktivieren, setze usingPersistStorage auf false:
let config = try? LogtoConfig(
// ...
usingPersistStorage: false
)
Implementiere An- und Abmeldung
Bevor wir ins Detail gehen, hier ein schneller Überblick über die Endbenutzererfahrung. Der Anmeldeprozess lässt sich wie folgt vereinfachen:
- Deine App löst die Anmeldemethode aus.
- Der Benutzer wird auf die Logto-Anmeldeseite umgeleitet. Bei nativen Apps wird der Systembrowser geöffnet.
- Der Benutzer meldet sich an und wird zurück zu deiner App umgeleitet (konfiguriert als Redirect-URI).
Bezüglich der umleitungsbasierten Anmeldung
- Dieser Authentifizierungsprozess folgt dem OpenID Connect (OIDC) Protokoll, und Logto erzwingt strenge Sicherheitsmaßnahmen, um die Benutzeranmeldung zu schützen.
- Wenn du mehrere Apps hast, kannst du denselben Identitätsanbieter (Logto) verwenden. Sobald sich der Benutzer bei einer App anmeldet, wird Logto den Anmeldeprozess automatisch abschließen, wenn der Benutzer auf eine andere App zugreift.
Um mehr über die Gründe und Vorteile der umleitungsbasierten Anmeldung zu erfahren, siehe Logto-Anmeldeerfahrung erklärt.
Configure redirect URI
- v2 (beta)
- v1
Wechseln wir zur Seite "Anwendungsdetails" der Logto-Konsole. Füge eine Redirect-URI io.logto.app://callback hinzu und klicke auf "Änderungen speichern".

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.
Wechseln wir zur Seite "Anwendungsdetails" der Logto-Konsole. Füge eine Redirect-URI io.logto://callback hinzu und klicke auf "Änderungen speichern".

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
Bevor du .signInWithBrowser(redirectUri:) aufrufst, stelle sicher, dass du die Redirect-URI im Admin Console korrekt konfiguriert hast.
- 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: Teste deine Anwendung
Jetzt kannst du deine Anwendung testen:
- Starte deine Anwendung, du wirst den Anmeldebutton sehen.
- Klicke auf den Anmeldebutton, das SDK wird den Anmeldeprozess initiieren und dich zur Logto-Anmeldeseite weiterleiten.
- Nachdem du dich angemeldet hast, wirst du zurück zu deiner Anwendung geleitet und siehst den Abmeldebutton.
- Klicke auf den Abmeldebutton, um den Token-Speicher zu leeren und dich abzumelden.
Benutzerinformationen abrufen
Benutzerinformationen anzeigen
Um die Informationen des Benutzers anzuzeigen, kannst du die Methode client.getIdTokenClaims() verwenden. Zum Beispiel in einer SwiftUI-App:
struct ContentView: View {
@State var isAuthenticated: Bool
@State var name: String?
init() {
isAuthenticated = client.isAuthenticated
name = try? client.getIdTokenClaims().name
}
var body: some View {
VStack {
if isAuthenticated {
Text("Willkommen, \(name)")
} else {
Text("Bitte anmelden")
}
}
}
}
Zusätzliche Ansprüche anfordern
Möglicherweise fehlen einige Benutzerinformationen im zurückgegebenen Objekt von client.getIdTokenClaims(). Dies liegt daran, dass OAuth 2.0 und OpenID Connect (OIDC) so konzipiert sind, dass sie dem Prinzip der minimalen Rechte (PoLP) folgen, und Logto auf diesen Standards basiert.
Standardmäßig werden begrenzte Ansprüche zurückgegeben. Wenn du mehr Informationen benötigst, kannst du zusätzliche Berechtigungen anfordern, um auf mehr Ansprüche zuzugreifen.
Ein "Anspruch (Claim)" ist eine Behauptung über ein Subjekt; eine "Berechtigung (Scope)" ist eine Gruppe von Ansprüchen. Im aktuellen Fall ist ein Anspruch ein Informationsstück über den Benutzer.
Hier ist ein nicht-normatives Beispiel für die Beziehung zwischen Berechtigung und Anspruch:
Der "sub"-Anspruch bedeutet "Subjekt", was der eindeutige Identifikator des Benutzers ist (d. h. Benutzer-ID).
Das Logto SDK wird immer drei Berechtigungen anfordern: openid, profile und offline_access.
Um zusätzliche Berechtigungen anzufordern, kannst du die Berechtigungen an das LogtoConfig-Objekt übergeben. Zum Beispiel:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Z.B. http://localhost:3001
appId: "<your-app-id>",
scopes: [
UserScope.Email.rawValue,
UserScope.Phone.rawValue,
]
)
Dann kannst du auf die zusätzlichen Ansprüche im Rückgabewert von client.getIdTokenClaims() zugreifen:
let claims = try? client.getIdTokenClaims()
// Jetzt kannst du auf zusätzliche Ansprüche `claims.email`, `claims.phone` usw. zugreifen.
Ansprüche, die Netzwerk-Anfragen benötigen
Um das ID-Token nicht aufzublähen, erfordern einige Ansprüche Netzwerk-Anfragen, um abgerufen zu werden. Zum Beispiel ist der custom_data Anspruch nicht im Benutzerobjekt enthalten, selbst wenn er in den Berechtigungen angefordert wird. Um auf diese Ansprüche zuzugreifen, kannst du die client.fetchUserInfo() Methode verwenden:
let userInfo = try? client.fetchUserInfo()
// Jetzt kannst du auf den Anspruch `userInfo.custom_data` zugreifen
Berechtigungen und Ansprüche
Logto verwendet die OIDC Scopes- und Claims-Konventionen, um die Berechtigungen (Scopes) und Ansprüche (Claims) für das Abrufen von Benutzerinformationen aus dem ID-Token und dem OIDC userinfo-Endpunkt zu definieren. Sowohl „Berechtigung (Scope)“ als auch „Anspruch (Claim)“ sind Begriffe aus den OAuth 2.0- und OpenID Connect (OIDC)-Spezifikationen.
Für Standard-OIDC-Ansprüche wird die Aufnahme in das ID-Token strikt durch die angeforderten Berechtigungen bestimmt. Erweiterte Ansprüche (wie custom_data und organizations) können zusätzlich so konfiguriert werden, dass sie im ID-Token über die Custom ID token-Einstellungen erscheinen.
Hier ist die Liste der unterstützten Berechtigungen (Scopes) und der entsprechenden Ansprüche (Claims):
Standard OIDC-Berechtigungen (Scopes)
openid (Standard)
| Claim-Name | Typ | Beschreibung |
|---|---|---|
| sub | string | Der eindeutige Identifikator des Benutzers |
profile (Standard)
| Claim-Name | Typ | Beschreibung |
|---|---|---|
| name | string | Der vollständige Name des Benutzers |
| username | string | Der Benutzername des Benutzers |
| picture | string | URL zum Profilbild des Endbenutzers. Diese URL MUSS auf eine Bilddatei (z. B. PNG, JPEG oder GIF) verweisen, nicht auf eine Webseite mit einem Bild. Beachte, dass diese URL speziell auf ein Profilfoto des Endbenutzers verweisen SOLLTE, das zur Darstellung des Endbenutzers geeignet ist, und nicht auf ein beliebiges vom Endbenutzer aufgenommenes Foto. |
| created_at | number | Zeitpunkt, zu dem der Endbenutzer erstellt wurde. Die Zeit wird als Anzahl der Millisekunden seit der Unix-Epoche (1970-01-01T00:00:00Z) dargestellt. |
| updated_at | number | Zeitpunkt, zu dem die Informationen des Endbenutzers zuletzt aktualisiert wurden. Die Zeit wird als Anzahl der Millisekunden seit der Unix-Epoche (1970-01-01T00:00:00Z) dargestellt. |
Weitere Standard-Ansprüche (Claims) wie family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo und locale werden ebenfalls im profile-Scope enthalten sein, ohne dass der userinfo-Endpunkt angefragt werden muss. Ein Unterschied zu den oben genannten Claims besteht darin, dass diese Claims nur zurückgegeben werden, wenn ihre Werte nicht leer sind, während die oben genannten Claims null zurückgeben, wenn die Werte leer sind.
Im Gegensatz zu den Standard-Claims verwenden die Claims created_at und updated_at Millisekunden anstelle von Sekunden.
email
| Claim-Name | Typ | Beschreibung |
|---|---|---|
string | Die E-Mail-Adresse des Benutzers | |
| email_verified | boolean | Ob die E-Mail-Adresse verifiziert wurde |
phone
| Claim-Name | Typ | Beschreibung |
|---|---|---|
| phone_number | string | Die Telefonnummer des Benutzers |
| phone_number_verified | boolean | Ob die Telefonnummer verifiziert wurde |
address
Bitte siehe die OpenID Connect Core 1.0 für Details zum Address-Claim.
Scopes, die mit (Standard) gekennzeichnet sind, werden immer vom Logto SDK angefordert. Claims unter den Standard-OIDC-Scopes sind immer im ID-Token enthalten, wenn der entsprechende Scope angefordert wird — sie können nicht deaktiviert werden.
Erweiterte Berechtigungen (Scopes)
Die folgenden Scopes sind von Logto erweitert und liefern Claims über den userinfo-Endpunkt. Diese Claims können auch so konfiguriert werden, dass sie direkt im ID-Token enthalten sind, über Konsole > Benutzerdefiniertes JWT. Siehe Benutzerdefiniertes ID-Token für weitere Details.
custom_data
| Claim-Name | Typ | Beschreibung | Standardmäßig im ID-Token enthalten |
|---|---|---|---|
| custom_data | object | Die benutzerdefinierten Daten des Benutzers |
identities
| Claim-Name | Typ | Beschreibung | Standardmäßig im ID-Token enthalten |
|---|---|---|---|
| identities | object | Die verknüpften Identitäten des Benutzers | |
| sso_identities | array | Die verknüpften SSO-Identitäten des Benutzers |
roles
| Claim-Name | Typ | Beschreibung | Standardmäßig im ID-Token enthalten |
|---|---|---|---|
| roles | string[] | Die Rollen (Roles) des Benutzers | ✅ |
urn:logto:scope:organizations
| Claim-Name | Typ | Beschreibung | Standardmäßig im ID-Token enthalten |
|---|---|---|---|
| organizations | string[] | Die Organisations-IDs, denen der Benutzer angehört | ✅ |
| organization_data | object[] | Die Organisationsdaten, denen der Benutzer angehört |
Diese Organisations-Claims können auch über den userinfo-Endpunkt abgerufen werden, wenn ein opaker Token verwendet wird. Allerdings können opake Tokens nicht als Organisationstoken für den Zugriff auf organisationsspezifische Ressourcen verwendet werden. Siehe Opaker Token und Organisationen für weitere Details.
urn:logto:scope:organization_roles
| Claim-Name | Typ | Beschreibung | Standardmäßig im ID-Token enthalten |
|---|---|---|---|
| organization_roles | string[] | Die Organisationsrollen, denen der Benutzer angehört, im Format <organization_id>:<role_name> | ✅ |
API-Ressourcen
Wir empfehlen, zuerst 🔐 Rollenbasierte Zugangskontrolle (RBAC) zu lesen, um die grundlegenden Konzepte von Logto RBAC zu verstehen und wie man API-Ressourcen richtig einrichtet.
Logto-Client konfigurieren
Sobald du die API-Ressourcen eingerichtet hast, kannst du sie bei der Konfiguration von Logto in deiner App hinzufügen:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>", // Z.B. http://localhost:3001
appId: "<your-app-id>",
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"], // API-Ressourcen hinzufügen
)
let client = LogtoClient(useConfig: config)
Jede API-Ressource hat ihre eigenen Berechtigungen (Berechtigungen).
Zum Beispiel hat die Ressource https://shopping.your-app.com/api die Berechtigungen shopping:read und shopping:write, und die Ressource https://store.your-app.com/api hat die Berechtigungen store:read und store:write.
Um diese Berechtigungen anzufordern, kannst du sie bei der Konfiguration von Logto in deiner App hinzufügen:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
scopes: ["shopping:read", "shopping:write", "store:read", "store:write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
)
let client = LogtoClient(useConfig: config)
Du wirst bemerken, dass Berechtigungen separat von API-Ressourcen definiert sind. Dies liegt daran, dass Resource Indicators for OAuth 2.0 spezifiziert, dass die endgültigen Berechtigungen für die Anfrage das kartesische Produkt aller Berechtigungen bei allen Zielservices sein werden.
Somit können im obigen Fall die Berechtigungen aus der Definition in Logto vereinfacht werden, beide API-Ressourcen können read und write Berechtigungen ohne Präfix haben. Dann, in der Logto-Konfiguration:
let config = try? LogtoConfig(
endpoint: "<your-logto-endpoint>",
appId: "<your-app-id>",
scopes: ["read", "write"],
resources: ["https://shopping.your-app.com/api", "https://store.your-app.com/api"],
)
let client = LogtoClient(useConfig: config)
Für jede API-Ressource wird sowohl read als auch write Berechtigungen angefordert.
Es ist in Ordnung, Berechtigungen anzufordern, die in den API-Ressourcen nicht definiert sind. Zum Beispiel kannst du die Berechtigung email anfordern, auch wenn die API-Ressourcen die Berechtigung email nicht verfügbar haben. Nicht verfügbare Berechtigungen werden sicher ignoriert.
Nach der erfolgreichen Anmeldung wird Logto die entsprechenden Berechtigungen an API-Ressourcen gemäß den Rollen des Benutzers ausstellen.
Zugangstoken für die API-Ressource abrufen
Um das Zugangstoken für eine spezifische API-Ressource abzurufen, kannst du die Methode getAccessToken verwenden:
let accessToken = try await client.getAccessToken(for: "https://shopping.your-app.com/api")
Diese Methode gibt ein JWT-Zugangstoken zurück, das verwendet werden kann, um auf die API-Ressource zuzugreifen, wenn der Benutzer die entsprechenden Berechtigungen hat. Wenn das aktuell zwischengespeicherte Zugangstoken abgelaufen ist, versucht diese Methode automatisch, ein Auffrischungstoken zu verwenden, um ein neues Zugangstoken zu erhalten.
Zugangstoken an Anfrage-Header anhängen
Platziere das Token im Authorization-Feld der HTTP-Header im Bearer-Format (Bearer YOUR_TOKEN), und du bist startklar.
Der Integrationsablauf des Bearer-Tokens kann je nach verwendetem Framework oder Anfrager variieren. Wähle deinen eigenen Weg, um den Anfrage-Authorization-Header anzuwenden.
await LogtoRequest.get(
useSession: session,
endpoint: userInfoEndpoint,
headers: ["Authorization": "Bearer \(accessToken)"]
)