Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 0 additions & 81 deletions .github/workflows/codeql.yml

This file was deleted.

12 changes: 6 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// swift-tools-version: 6.2
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "OAuthKit",
platforms: [
.iOS(.v26),
.macOS(.v26),
.tvOS(.v26),
.visionOS(.v26),
.watchOS(.v26)
.iOS(.v17),
.macOS(.v15),
.tvOS(.v18),
.visionOS(.v1),
.watchOS(.v10)
],
products: [
.library(
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
![Build](https://github.com/codefiesta/OAuthKit/actions/workflows/swift.yml/badge.svg)
![Swift 6.2+](https://img.shields.io/badge/Swift-6.2%2B-gold.svg)
![Swift 6.1+](https://img.shields.io/badge/Swift-6.1%2B-gold.svg)
![Xcode 26.0+](https://img.shields.io/badge/Xcode-26.0%2B-tomato.svg)
![iOS 26.0+](https://img.shields.io/badge/iOS-26.0%2B-crimson.svg)
![macOS 26.0+](https://img.shields.io/badge/macOS-26.0%2B-skyblue.svg)
![tvOS 26.0+](https://img.shields.io/badge/tvOS-26.0%2B-blue.svg)
![visionOS 26.0+](https://img.shields.io/badge/visionOS-26.0%2B-violet.svg)
![watchOS 26.0+](https://img.shields.io/badge/watchOS-26.0%2B-magenta.svg)
![iOS 17.0+](https://img.shields.io/badge/iOS-17.0%2B-crimson.svg)
![macOS 15.0+](https://img.shields.io/badge/macOS-15.0%2B-skyblue.svg)
![tvOS 18.0+](https://img.shields.io/badge/tvOS-18.0%2B-blue.svg)
![visionOS 1.0+](https://img.shields.io/badge/visionOS-1.0%2B-violet.svg)
![watchOS 10.0+](https://img.shields.io/badge/watchOS-10.0%2B-magenta.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-indigo.svg)](https://opensource.org/licenses/MIT)
![Code Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/codefiesta/87655b6e3c89b9198287b2fefbfa641f/raw/oauthkit-coverage.json)

Expand Down Expand Up @@ -36,11 +36,11 @@ Key features include:

## OAuthKit Installation

OAuthKit can be installed using [Swift Package Manager](https://www.swift.org/documentation/package-manager/). If you need to build with Swift Tools `6.1` and Apple APIs > `26.0` use version [1.5.1](https://github.com/codefiesta/OAuthKit/releases/tag/1.5.1).
OAuthKit can be installed using [Swift Package Manager](https://www.swift.org/documentation/package-manager/).

```swift
dependencies: [
.package(url: "https://github.com/codefiesta/OAuthKit", from: "2.0.1")
.package(url: "https://github.com/codefiesta/OAuthKit", from: "2.1.0")
]
```

Expand Down
53 changes: 35 additions & 18 deletions Sources/OAuthKit/OAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ public final class OAuth: Sendable {
#if os(macOS) || os(iOS) || os(visionOS)
@ObservationIgnored
var context: LAContext = .init()

var policy: LAPolicy = {
#if os(macOS) || os(iOS)
if #available(macOS 15.0, iOS 18.0, *) {
return .deviceOwnerAuthenticationWithBiometricsOrCompanion
}
return .deviceOwnerAuthenticationWithBiometrics
#else
return .deviceOwnerAuthenticationWithBiometrics
#endif
}()

#endif

@ObservationIgnored
Expand Down Expand Up @@ -117,15 +129,15 @@ public extension OAuth {
state = .authorizing(provider, grantType)
case .deviceCode:
state = .requestingDeviceCode(provider)
Task.immediate {
task { [self] in
await requestDeviceCode(provider: provider)
}
case .clientCredentials:
Task.immediate {
task { [self] in
await requestClientCredentials(provider: provider)
}
case .refreshToken:
Task.immediate {
task { [self] in
await refreshToken(provider: provider)
}
}
Expand All @@ -138,7 +150,7 @@ public extension OAuth {
/// - code: the code to exchange
/// - pkce: the pkce data
func token(provider: Provider, code: String, pkce: PKCE? = nil) {
Task.immediate {
task { [self] in
await requestToken(provider: provider, code: code, pkce: pkce)
}
}
Expand Down Expand Up @@ -233,19 +245,12 @@ private extension OAuth {

#if os(macOS) || os(iOS) || os(visionOS)
let localizedReason = context.localizedReason.isNotEmpty ? context.localizedReason: defaultAuthenticationWithBiometricsOrCompanionReason
#if os(macOS) || os(iOS)
let policy: LAPolicy = .deviceOwnerAuthenticationWithBiometricsOrCompanion
#else
let policy: LAPolicy = .deviceOwnerAuthenticationWithBiometrics
#endif
var error: NSError?
if context.canEvaluatePolicy(policy, error: &error) {
context.evaluatePolicy(policy, localizedReason: localizedReason) { [weak self] success, error in
guard let self else { return }
Task.immediate { @MainActor in
if success {
self.loadAuthorizations()
}
guard let self, success else { return }
Task { @MainActor [self] in
loadAuthorizations()
}
}
}
Expand All @@ -257,7 +262,7 @@ private extension OAuth {

/// Starts the network monitor.
func monitor() {
Task {
task { [self] in
await networkMonitor.start()
}
}
Expand All @@ -284,7 +289,7 @@ private extension OAuth {
let timeInterval: TimeInterval = .init(deviceCode.interval)
let task = Task.delayed(timeInterval: timeInterval) { [weak self] in
guard let self else { return }
await self.poll(provider: provider, deviceCode: deviceCode)
await poll(provider: provider, deviceCode: deviceCode)
}
tasks.append(task)
}
Expand All @@ -304,18 +309,30 @@ private extension OAuth {
// Schedule the auto refresh task
let task = Task.delayed(timeInterval: timeInterval) { [weak self] in
guard let self else { return }
await self.refreshToken(provider: provider)
await refreshToken(provider: provider)
}
tasks.append(task)
} else {
// Execute the task immediately
Task.immediate {
task { [self] in
await refreshToken(provider: provider)
}
}
}
}
}

/// Create and immediately start running a new detached task in the context of this actor.
/// - Parameters:
/// - priority: the task priority
/// - operation: the operation to be run immediately upon entering the task.
func task(priority: TaskPriority = .high, operation: sending @escaping @isolated(any) () async throws -> Void) {
if #available(macOS 26, iOS 26, watchOS 26, tvOS 26, visionOS 26, *) {
Task.immediate(operation: operation)
} else {
Task(priority: priority, operation: operation)
}
}
}

// MARK: URLRequests
Expand Down