OAuth 2.0 and JWT Authorization in Swift: A Practical Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why OAuth 2.0 and JWT Are the Standard for iOS Apps

\n

Modern mobile applications rarely work in isolation. Most of them interact with remote APIs, requiring secure user authentication and authorization. In the Apple ecosystem (iOS, macOS, watchOS), the de facto standard has become the combination of OAuth 2.0 (an access delegation protocol) and JWT (JSON Web Token — a compact token format). This combination provides flexibility, security, and ease of integration.

\n

In this article, we will not delve into dry theory. Instead, we will walk through a practical implementation in Swift. You will learn how to obtain an access token via OAuth 2.0, how to securely store it in Keychain, how to decode JWT on the client side, and how to refresh tokens without user intervention. All code examples are ready for use in a real project.

\n\n

1. OAuth 2.0 Architecture in Swift: From Request to Token

\n

First, let's define the flow. In mobile applications, the Authorization Code Flow with PKCE (Proof Key for Code Exchange) is most commonly used. This is the most secure option for public clients (mobile applications cannot store a secret).

\n

Let's create a structure for OAuth configuration:

\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

The first step is to form the authorization URL. For PKCE, we need to generate a codeVerifier and its SHA256 hash — 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

Now we form the URL to open in the browser (via 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

After successful authorization, the user will be redirected to redirectURI with a code parameter. This code is exchanged for tokens:

\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

Book Recommendations