This episode covers authentication and authorization in Swift apps: implementing the OAuth 2.0 and OpenID Connect flow, integrating Sign in with Apple, managing access tokens and refresh tokens, plus consuming APIs securely with attention to HTTP security headers and session security.

Authentication proves who the user is; authorization determines what they're allowed to do. Episode 12 covers authentication and authorization in Swift apps: the OAuth 2.0 and OpenID Connect flow, integrating Sign in with Apple, and managing tokens correctly.
The most common mistake in the field isn't the login part, but token management afterward — tokens stored in the wrong place, expirations not handled, or refreshes done without protection. This episode builds the right habits from the start.
OAuth 2.0 is an authorization framework, while OpenID Connect (OIDC) adds an authentication layer on top of it. The Authorization Code flow with PKCE is the standard pattern for mobile apps:
The exchange can be tested directly with curl:
curl -X POST https://auth.example.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTH_CODE" \
-d "client_id=CLIENT_ID" \
-d "redirect_uri=myapp://callback"curl -X POST ... -d "grant_type=authorization_code" exchanges an authorization code for tokens. On mobile, this flow runs through ASWebAuthenticationSession, which opens login in the system's most secure browser.
The access token is sent via the Authorization header:
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let (data, response) = try await URLSession.shared.data(for: request)request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") authenticates the request. The Bearer format is the OAuth 2.0 standard. Access tokens are short-lived — typically 15 minutes to 1 hour — to limit the impact if one leaks.
Sign in with Apple is a built-in identity provider that makes password-free login easy. Users only need Face ID or Touch ID, and their account is authenticated instantly. Its key differentiator: a one-tap login with Email Relay and an "Sign In with Apple" stop button.
Basic integration involves two parties:
ASAuthorizationAppleIDButton; the authentication result is an identity token and an authorization code.The identity token received by the client is a JWT signed by Apple:
echo "$IDENTITY_TOKEN" | cut -d. -f2 | base64 -decho "$IDENTITY_TOKEN" | cut -d. -f2 | base64 -d decodes the JWT payload to see claims such as sub, email, and email_verified. Never trust a token without verifying the signature and issuer on the server side.
Access tokens are stored in the Keychain (episode 11), not UserDefaults. Refresh tokens — far more sensitive because they're long-lived — also go in the Keychain, ideally with restricted access:
func tokenBaru() async throws -> String {
var request = URLRequest(url: URL(string: "https://auth.example.com/token")!)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded",
forHTTPHeaderField: "Content-Type")
let body = "grant_type=refresh_token&refresh_token=\(refreshToken)"
request.httpBody = Data(body.utf8)
let (data, _) = try await URLSession.shared.data(for: request)
let hasil = try JSONDecoder().decode(TokenResponse.self, from: data)
return hasil.accessToken
}"grant_type=refresh_token&refresh_token=\(refreshToken)" exchanges the refresh token for a new access token. When an API request fails with status 401, the app refreshes once then retries the request — a pattern that keeps users logged in without interruption.
Some key session security rules:
For web servers, also pay attention to security headers such as Strict-Transport-Security and X-Content-Type-Options — habits we'll deepen in episode 13.
Warning
Never store tokens in UserDefaults. A rooted or jailbroken device can extract them; the Keychain with proper access control adds an extra layer of protection.
Secure API consumption means validating every response — not just the HTTP status, but also the data structure and the values within. Use strict response types with Codable, and don't surface data you weren't expecting. Encode authorization claims into the model: only fetch data the user is actually entitled to.
On the app side, watch for a sudden spike in 401s as a signal of a leaked token or a revoked session. Combine this with structured logging (episode 21) so your team can detect abuse early.
Key takeaways:
Bearer in the Authorization header.In the next episode, episode 13, we'll cover networking security and best practices — HTTPS and TLS, certificate pinning, secure network configuration on iOS and macOS, API request signing, secure headers, and observability for network failures with retry policies. Your networking becomes a fortress!