OAuth 2.0 und JWT-Autorisierung in Swift: Ein praktischer Leitfaden

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum OAuth 2.0 und JWT der Standard für iOS-Apps sind

\n

Moderne mobile Anwendungen arbeiten selten isoliert. Die meisten interagieren mit entfernten APIs und erfordern eine sichere Authentifizierung und Autorisierung des Benutzers. Im Apple-Ökosystem (iOS, macOS, watchOS) ist die Kombination aus OAuth 2.0 (Delegierungsprotokoll für Zugriffe) und JWT (JSON Web Token – kompaktes Token-Format) zum De-facto-Standard geworden. Diese Kombination bietet Flexibilität, Sicherheit und Integrationskomfort.

\n

In diesem Artikel werden wir nicht in die trockene Theorie eintauchen. Stattdessen werden wir eine praktische Implementierung in Swift durchgehen. Sie erfahren, wie Sie ein Zugriffstoken über OAuth 2.0 erhalten, es sicher in der Keychain speichern, JWT auf dem Client decodieren und Tokens ohne Benutzereingriff aktualisieren. Alle Codebeispiele sind bereit für den Einsatz in einem echten Projekt.

\n\n

1. OAuth 2.0-Architektur in Swift: Von der Anfrage zum Token

\n

Zunächst legen wir den Ablauf (Flow) fest. In mobilen Apps wird am häufigsten der Authorization Code Flow mit PKCE (Proof Key for Code Exchange) verwendet. Dies ist die sicherste Option für öffentliche Clients (mobile Apps können kein Geheimnis speichern).

\n

Wir erstellen eine Struktur für die OAuth-Konfiguration:

\n
struct OAuthConfig {\n    let clientID: String\n    let redirectURI: String\n    let authorizationEndpoint: String\n    let tokenEndpoint: String\n    let scope: String\n}
\n

Der erste Schritt ist die Erstellung der URL für die Autorisierung. Für PKCE benötigen wir einen generierten codeVerifier und seinen SHA256-Hash – den codeChallenge:

\n
import Foundation\nimport CommonCrypto\n\nclass PKCEGenerator {\n    static func generateCodeVerifier() -> String {\n        var buffer = [UInt8](repeating: 0, count: 32)\n        _ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)\n        return Data(buffer).base64URLEncodedString()\n    }\n    \n    static func generateCodeChallenge(from verifier: String) -> String {\n        guard let data = verifier.data(using: .utf8) else { return "" }\n        var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))\n        data.withUnsafeBytes { \n            _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)\n        }\n        return Data(hash).base64URLEncodedString()\n    }\n}\n\nextension Data {\n    func base64URLEncodedString() -> String {\n        return self.base64EncodedString()\n            .replacingOccurrences(of: "+", with: "-")\n            .replacingOccurrences(of: "/", with: "_")\n            .replacingOccurrences(of: "=", with: "")\n    }\n}
\n

Jetzt erstellen wir die URL, die im Browser geöffnet wird (über ASWebAuthenticationSession):

\n
func buildAuthorizationURL(config: OAuthConfig, codeChallenge: String) -> URL? {\n    var components = URLComponents(string: config.authorizationEndpoint)\n    components?.queryItems = [\n        URLQueryItem(name: "response_type", value: "code"),\n        URLQueryItem(name: "client_id", value: config.clientID),\n        URLQueryItem(name: "redirect_uri", value: config.redirectURI),\n        URLQueryItem(name: "scope", value: config.scope),\n        URLQueryItem(name: "code_challenge", value: codeChallenge),\n        URLQueryItem(name: "code_challenge_method", value: "S256")\n    ]\n    return components?.url\n}
\n

Nach erfolgreicher Autorisierung wird der Benutzer auf die redirectURI mit dem Parameter code weitergeleitet. Dieser Code wird gegen Tokens eingetauscht:

\n
func exchangeCodeForToken(config: OAuthConfig, code: String, codeVerifier: String) async throws -> TokenResponse {\n    let url = URL(string: config.tokenEndpoint)!\n    var request = URLRequest(url: url)\n    request.httpMethod = "POST"\n    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")\n    \n    let body = "grant_type=authorization_code" +\n               "&co                

Blogs

Buchempfehlungen