Introduction: Why is authorization needed in mobile applications?
Modern iOS apps rarely work in isolation. They communicate with servers, send data, and receive personalized content. But how does the server know that the request was sent by the user it claims to be? This is where OAuth 2.0 and JWT (JSON Web Token) come to the rescue. These are not just trendy acronyms, but security standards that underpin most modern APIs (Google, Facebook, GitHub, your own backend).
In this article, we will break down how OAuth 2.0 and JWT work in Swift. You will learn how they differ, how to implement them correctly, and what pitfalls await a beginner. We will write code for obtaining, storing, and refreshing tokens. Let's go!
1. Basics: OAuth 2.0 and JWT — What's the difference?
Many people confuse these two concepts. In fact, they are different levels of abstraction.
- OAuth 2.0 is an authorization protocol. It describes how an application (client) can gain access to a user's resources on a third-party server (e.g., their photos on Google) without passing along a login and password. The main idea is issuing temporary access tokens.
- JWT is a token format. It is a compact, URL-safe string that contains JSON data (e.g., user id, role, expiration date) and a signature. JWT is often used as an access token in OAuth 2.0, but can also be used independently.
A simple analogy: OAuth 2.0 is the rules for issuing a stadium pass, while JWT is the plastic pass itself with your photo and stamp.
In a typical scenario, an iOS application:
- Opens a browser to log in via an OAuth provider (Google, Apple ID, your own server).
- Receives an authorization code.
- Exchanges the code for an access token (often in JWT format) and a refresh token.
- Uses the access token for API requests.
- When the access token expires, uses the refresh token to obtain a new one.
2. JWT Token Structure
A JWT consists of three parts, separated by dots:
header.payload.signatureExample of a decoded JWT:
// Header{ "alg": "HS256", "typ": "JWT"}// Payload{ "sub": "1234567890", "name": "Ivan Petrov", "iat": 1516239022, "exp": 1516242622}// Signature - created by the serverImportant: The JWT payload is not encrypted, it is only Base64 encoded. Anyone can read it. The signature provides secrecy — if the server sees that the signature does not match, it rejects the token. Therefore, never store passwords or secret data in a JWT.
3. Implementing OAuth 2.0 and JWT in Swift
Now let's move to practice. We will write a class for working with authorization. For simplicity, we will use the built-in URLSession, although real projects often use Alamofire or SwiftUI + async/await.
3.1. Data Models
struct AuthResponse: Codable { let accessToken: String let refreshToken: String? let expiresIn: Int enum CodingKeys: String, CodingKey { case accessToken = "access_token" case refreshToken = "refresh_token" case expiresIn = "expires_in" }}
struct UserProfile: Codable { let id: String let name: String let email: String}3.2. Authorization Service
Let's create a class AuthService that will be responsible for obtaining and refreshing tokens. Note: in a real application, the URL and clientSecret should be stored securely (e.g., in Keychain or via a configuration server).
class AuthService { static let shared = A