NNovaNetworkClientSwift networkingGitHub ↗

Intermediate · 14 min

Sign in with OAuth 2.0

PKCE, the token exchange, and one refresh shared by every caller.

You’ll buildA client that attaches a token, refreshes it once, and asks for a sign-in when the session really is over.
1
Step 1

Start the flow

Keep the verifier and the state. The callback is worthless without them, and the state check is what stops someone else's authorization code being redeemed in your user's session.

SigninwithOAuth2.0.swift
let pkce = PKCEChallenge.generate()
let state = UUID().uuidString
let url = try oauth.authorizationURL(state: state, challenge: pkce)
// The app opens `url`: presenting a browser needs a window
// anchor, which is the app's job, not the library's.
2
Step 2

Validate what comes back

The state is checked before anything else is read, and a mismatch throws without returning the code.

SigninwithOAuth2.0.swift
let code = try oauth.authorizationCode(
    from: callbackURL,
    expectedState: state
)
let token = try await oauth.exchange(code: code, verifier: pkce.verifier)
try await authenticator.setToken(token)
3
Step 3

Wire it into the client

The client already coordinates a single refresh across a burst of 401s and replays them. This fills in the closure it takes.

SigninwithOAuth2.0.swift
var configuration = NetworkClientConfiguration()
configuration.authRefreshProvider = authenticator.refreshProvider
configuration.middleware = [authenticator.middleware]
let client = NetworkClient(configuration: configuration)
4
Step 4

Let eight callers need a token at once

An actor is not enough on its own: it suspends at the network call, so a second caller would start a second refresh. Sharing the in-flight task means the provider sees one request.

SigninwithOAuth2.0.swift
await withTaskGroup(of: Void.self) { group in
    for _ in 0..<8 {
        group.addTask { _ = try? await authenticator.validToken() }
    }
}
// The provider saw exactly one refresh.
✓

Tutorial complete

A client that attaches a token, refreshes it once, and asks for a sign-in when the session really is over.