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
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ orbs:
executors:
apple-ci-arm-medium:
macos:
xcode: "16.2.0"
xcode: "26.2.0"
resource_class: m4pro.medium

commands:
prepare-ios-simulator:
steps:
- macos/preboot-simulator:
version: "18.2"
version: "18.6"
platform: "iOS"
device: "iPhone 16 Pro Max"

prepare-tvos-simulator:
steps:
- macos/preboot-simulator:
version: "18.2"
version: "18.5"
platform: "tvOS"
device: "Apple TV"

Expand Down
1 change: 1 addition & 0 deletions Sources/AuthFoundation/Responses/OpenIdConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ extension OpenIdConfiguration {
public var endSessionEndpoint: URL? { self[.endSessionEndpoint] }
public var introspectionEndpoint: URL? { self[.introspectionEndpoint] }
public var deviceAuthorizationEndpoint: URL? { self[.deviceAuthorizationEndpoint] }
public var pushedAuthorizationRequestEndpoint: URL? { self[.pushedAuthorizationRequestEndpoint] }
public var registrationEndpoint: URL? { self[.registrationEndpoint] }
public var revocationEndpoint: URL? { self[.revocationEndpoint] }
public var userinfoEndpoint: URL? { self[.userinfoEndpoint] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extension OpenIdConfiguration {
case userinfoSigningAlgValuesSupported = "userinfo_signing_alg_values_supported"
case userinfoEncryptionAlgValuesSupported = "userinfo_encryption_alg_values_supported"
case userinfoEncryptionEncValuesSupported = "userinfo_encryption_enc_values_supported"
case pushedAuthorizationRequestEndpoint = "pushed_authorization_request_endpoint"
case requestObjectSigningAlgValuesSupported = "request_object_signing_alg_values_supported"
case requestObjectEncryptionAlgValuesSupported = "request_object_encryption_alg_values_supported"
case requestObjectEncryptionEncValuesSupported = "request_object_encryption_enc_values_supported"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ extension AuthorizationCodeFlow {
authenticationURL = nil
}
}

/// Utilize Pushed Authorization Requests (PAR) if supported by the Authorization Server.
public var pushedAuthorizationRequestEnabled: Bool = true
Comment thread
AlexNachbaur marked this conversation as resolved.


/// The logical name of the target API or resource server
/// ([RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)).
Expand Down
30 changes: 28 additions & 2 deletions Sources/OAuth2Auth/Authentication/AuthorizationCodeFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,34 @@

return try await withExpression {
var context = context
let url = try self.createAuthenticationURL(from: try await client.openIdConfiguration().authorizationEndpoint,
using: context)
let openIdConfiguration = try await client.openIdConfiguration()

var parUrl: URL?
if context.pushedAuthorizationRequestEnabled,
let parRequestUrl = openIdConfiguration.pushedAuthorizationRequestEndpoint
{
let request = PushedAuthorizationRequest(url: parRequestUrl,
clientConfiguration: client.configuration,
additionalParameters: additionalParameters,
context: context)
let response = try await request.send(to: client).result
var components = URLComponents(url: openIdConfiguration.authorizationEndpoint,
resolvingAgainstBaseURL: true)
components?.queryItems = [
.init(name: "client_id", value: client.configuration.clientId),
.init(name: "request_uri", value: response.requestUri),
]
parUrl = components?.url
}

let url: URL
if let parUrl {
url = parUrl
} else {
url = try createAuthenticationURL(from: openIdConfiguration.authorizationEndpoint,
using: context)
}

context.authenticationURL = url
_context = context

Expand Down Expand Up @@ -279,7 +305,7 @@

/// Continues an authentication flow using the given authentication redirect URI.
///
/// Once the user completes authorization by opening the authorization URL returned by the ``start(with:completion:)`` function within a browser, the browser will return a URL that matches the scheme provided in the client configuration's ``OAuth2Client/Configuration/redirectUri``. This URI will contain either an error response from the authorization server, or an authorization code which can be used to exchange a token.

Check warning on line 308 in Sources/OAuth2Auth/Authentication/AuthorizationCodeFlow.swift

View workflow job for this annotation

GitHub Actions / Build Documentation Archives

Documentation warning

'OAuth2Client' doesn't exist at '/OAuth2Auth/AuthorizationCodeFlow/resume(with:completion:)'
///
/// This method takes the returned redirect URI, and communicates with Okta to exchange that for a token.
/// - Parameters:
Expand Down
3 changes: 3 additions & 0 deletions Sources/OAuth2Auth/Authentication/SessionTokenFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@

/// Initializer that uses the predefined OAuth2Client
/// - Parameters:
/// - client: ``OAuth2Client`` client instance to authenticate with.

Check warning on line 81 in Sources/OAuth2Auth/Authentication/SessionTokenFlow.swift

View workflow job for this annotation

GitHub Actions / Build Documentation Archives

Documentation warning

'OAuth2Client' doesn't exist at '/OAuth2Auth/SessionTokenFlow/init(client:additionalParameters:)'
/// - additionalParameters: Optional query parameters to supply tot he authorization server for all requests from this flow.
public init(client: OAuth2Client,
additionalParameters: [String: any APIRequestArgument]? = nil) throws
Expand All @@ -103,6 +103,9 @@
public func start(with sessionToken: String,
context: Context = .init()) async throws -> Token
{
var context = context
context.pushedAuthorizationRequestEnabled = false

_isAuthenticating = true
_context = context

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ import Foundation
import AuthFoundation

extension AuthorizationCodeFlow {
struct PushedAuthorizationResponse: Codable {
let requestUri: String
let expiresIn: Int

enum CodingKeys: String, CodingKey {
case requestUri = "request_uri"
case expiresIn = "expires_in"
}
}

struct PushedAuthorizationRequest: AuthenticationFlowRequest {
typealias Flow = AuthorizationCodeFlow

let url: URL
let clientConfiguration: OAuth2Client.Configuration
let additionalParameters: [String: any APIRequestArgument]?
let context: Flow.Context
}

struct TokenRequest: OAuth2TokenRequest, AuthenticationFlowRequest {
typealias Flow = AuthorizationCodeFlow

Expand Down Expand Up @@ -59,3 +78,18 @@ extension AuthorizationCodeFlow.TokenRequest {
}

extension AuthorizationCodeFlow.TokenRequest: APIParsingContext {}

extension AuthorizationCodeFlow.PushedAuthorizationRequest: APIRequest, APIRequestBody {
typealias ResponseType = AuthorizationCodeFlow.PushedAuthorizationResponse

var httpMethod: APIRequestMethod { .post }
var contentType: APIContentType? { .formEncoded }
var acceptsType: APIContentType? { .json }
var category: OAuth2APIRequestCategory { .authorization }
var bodyParameters: [String: any APIRequestArgument]? {
var result = additionalParameters ?? [:]
result.merge(clientConfiguration.parameters(for: category))
result.merge(context.parameters(for: category))
return result
}
}
Loading