feat: Add authorizeWithRequestUri method for PAR-based authentication#1038
feat: Add authorizeWithRequestUri method for PAR-based authentication#1038subhankarmaiti wants to merge 9 commits intomasterfrom
authorizeWithRequestUri method for PAR-based authentication#1038Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds support for PAR (Pushed Authorization Request) flows in the SDK, enabling Backend-For-Frontend (BFF) authentication patterns. The new startForCode(requestURI:) method returns only the authorization code instead of performing token exchange, allowing backends to handle the secure token exchange using their client secret.
Key changes:
- Introduces new
startForCode(requestURI:)API with callback, async/await, and Combine variants - Returns
AuthorizationCodestruct containing the code and optional state parameter - Implements
PARCodeTransactionto handle the authorization flow without token exchange
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| Auth0/WebAuth.swift | Added protocol definitions for startForCode(requestURI:) methods with comprehensive documentation |
| Auth0/Auth0WebAuth.swift | Implemented startForCode methods and PAR-specific authorize URL builder |
| Auth0/AuthorizationCode.swift | New public struct to encapsulate authorization code and state from PAR callbacks |
| Auth0/PARCodeTransaction.swift | New transaction handler for PAR code flows, similar to LoginTransaction but returns codes instead of credentials |
| Auth0Tests/PARCodeTransactionSpec.swift | Comprehensive test coverage for PARCodeTransaction including success, error, and cancellation scenarios |
| EXAMPLES.md | Added PAR usage documentation with examples for callback, async/await, and Combine patterns |
| Auth0.xcodeproj/project.pbxproj | Updated project file to include new source files in build targets |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
startForCode method for PAR-based authenticationauthorizeWithRequestUri method for PAR-based authentication
| } | ||
|
|
||
| private func buildPARAuthorizeURL(requestURI: String) -> URL { | ||
| guard let authorize = self.overrideAuthorizeURL ?? URL(string: "authorize", relativeTo: self.url), |
There was a problem hiding this comment.
naming can be authorizeURL
| // Step 4: Send code to BFF to exchange for tokens | ||
| let credentials = try await yourBffClient.exchangeCode(authorizationCode.code) | ||
| credentialsManager.store(credentials: credentials) | ||
| } catch let error as WebAuthError where error.isUserCancelled { |
There was a problem hiding this comment.
error handling can be kept uniform across async await and combine example
| let provider = self.provider ?? WebAuthentication.asProvider(redirectURL: redirectURL, | ||
| ephemeralSession: ephemeralSession, | ||
| headers: headers) | ||
| let userAgent = provider(authorizeURL) { [storage, barrier, onCloseCallback] result in |
There was a problem hiding this comment.
Lets update this to use weak self and refer to storage and barrier via self inside the closure. Capturing them strongly poses a risk of memory leaks. I’ve noticed that in some of the existing code we are capturing these strongly, so it would be great to do refactoring there too
|
|
||
| private(set) var userAgent: WebAuthUserAgent? | ||
|
|
||
| let redirectURL: URL |
There was a problem hiding this comment.
nit: all of these data members could be private if they aint being called internally from other structs/classes.
|
|
||
| let authorizeURL = self.buildPARAuthorizeURL(requestURI: requestURI) | ||
|
|
||
| let provider = self.provider ?? WebAuthentication.asProvider(redirectURL: redirectURL, |
There was a problem hiding this comment.
The provider property can take headers as parameters. Are those header values something that we need to pass to the authorize end point ?
| } | ||
|
|
||
| private func handleCallback(url: URL) -> Bool { | ||
| guard url.absoluteString.lowercased().hasPrefix(self.redirectURL.absoluteString.lowercased()), |
There was a problem hiding this comment.
nit: lets avoid lowercased() for the full uri here it would create false positives for this validation. we could have lowercased() for scheme and domain
| if let fragment = components.fragment { | ||
| let fragmentItems = fragment.split(separator: "&").compactMap { pair -> (String, String)? in | ||
| let parts = pair.split(separator: "=", maxSplits: 1) | ||
| guard parts.count == 2 else { return nil } | ||
| return (String(parts[0]), String(parts[1])) | ||
| } | ||
| fragmentItems.forEach { items[$0.0] = $0.1 } | ||
| } | ||
|
|
There was a problem hiding this comment.
could not find the usage of fragments in subsequent code flow. if we do need fragment parsing we can put a fragment parser in utility or else please remove this
Adds
authorizeWithRequestUri(requestURI:)method toWebAuthprotocol for PAR (Pushed Authorization Request) flows that return the authorization code instead of credentials.New API