feat: auth improvements (#217)

* feat: improvement to oauth resources resolution

* feat: improvements to refreshToken procedure and updates to unit tests

* feat: improvements to documentation of clien_id
This commit is contained in:
yehorsobko 2026-04-17 16:34:59 +02:00 • committed by GitHub
commit cb6a62f7c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -217,7 +217,6 @@ public final class OAuthAuthorizer: HTTPClientAuthorizer, @unchecked Sendable {
return nil
}
if accessToken.isExpired() {
tokenStorage.clear()
return nil
}
return "\(OAuthTokenType.bearer) \(accessToken.value)"
@ -367,7 +366,6 @@ public final class OAuthAuthorizer: HTTPClientAuthorizer, @unchecked Sendable {
public func prepareAuthorization(for endpoint: URL, session: URLSession) async throws {
guard configuration.proactiveRefreshWindowSeconds > 0 else { return }
guard let token = tokenStorage.load() else { return }
guard !token.isExpired() else { return }
guard token.isExpired(skewSeconds: configuration.proactiveRefreshWindowSeconds) else {
return
}
@ -441,8 +439,10 @@ public final class OAuthAuthorizer: HTTPClientAuthorizer, @unchecked Sendable {
candidates.append(fallback)
}
let fallbackIssuer = try? discoveryClient.metadataDiscovery
.authorizationServerFallbackIssuer(from: endpoint)
let metadata = try await discoveryClient.fetchProtectedResourceMetadata(
candidates: candidates, session: session)
candidates: candidates, fallbackIssuer: fallbackIssuer, session: session)
try validateProtectedResource(metadata: metadata, endpoint: endpoint)
self.protectedResourceMetadata = metadata
@ -716,10 +716,17 @@ public final class OAuthAuthorizer: HTTPClientAuthorizer, @unchecked Sendable {
expiresAt: expiresAt,
scopes: scopeSet,
authorizationServer: selectedAuthorizationServer,
refreshToken: decoded.refreshToken
refreshToken: decoded.refreshToken,
clientID: nonEmptyClientID()
))
}
/// Returns the configured `client_id` or `nil` if the authorizer has not yet been assigned one.
private func nonEmptyClientID() -> String? {
let id = configuration.authentication.clientID
return id.isEmpty ? nil : id
}
private func resolveTokenEndpoint(
asMetadata: OAuthAuthorizationServerMetadata
) throws -> URL {
@ -823,7 +830,8 @@ public final class OAuthAuthorizer: HTTPClientAuthorizer, @unchecked Sendable {
expiresAt: nil,
scopes: requestedScopes ?? [],
authorizationServer: authorizationServer,
refreshToken: nil
refreshToken: nil,
clientID: nonEmptyClientID()
))
}