Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds ability to injects additional headers to token end points. #503

Closed
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
18 changes: 18 additions & 0 deletions Auth0/Auth0Authentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,24 @@ struct Auth0Authentication: Authentication {
logger: self.logger,
telemetry: self.telemetry)
}

func renew(withRefreshToken refreshToken: String, scope: String? = nil, headers: [String: String] = [:]) -> Request<Credentials, AuthenticationError> {
var payload: [String: Any] = [
"refresh_token": refreshToken,
"grant_type": "refresh_token",
"client_id": self.clientId
]
payload["scope"] = scope
let oauthToken = URL(string: "/oauth/token", relativeTo: self.url)!
return Request(session: session,
url: oauthToken,
method: "POST",
handle: authenticationObject,
payload: payload,
headers: headers,
logger: self.logger,
telemetry: self.telemetry)
}

func revoke(refreshToken: String) -> Request<Void, AuthenticationError> {
let payload: [String: Any] = [
Expand Down
12 changes: 12 additions & 0 deletions Auth0/Authentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,18 @@ public protocol Authentication: Trackable, Loggable {
- returns: a request that will yield Auth0 user's credentials
*/
func renew(withRefreshToken refreshToken: String, scope: String?) -> Request<Credentials, AuthenticationError>


/**
Renew user's credentials with a refresh_token grant for `/oauth/token`
If you are not using OAuth 2.0 API Authorization please use `delegation(parameters:)`
- parameter refreshToken: the client's refresh token
- parameter scope: scopes to request for the new tokens. By default is nil which will ask for the same ones requested during Auth.
- parameter headers: Adds header to request object
- important: This method only works for a refresh token obtained after auth with OAuth 2.0 API Authorization.
- returns: a request that will yield Auth0 user's credentials
*/
func renew(withRefreshToken refreshToken: String, scope: String?, headers: [String: String]) -> Request<Credentials, AuthenticationError>

/**
Revoke a user's refresh_token with a call to `/oauth/revoke`
Expand Down
14 changes: 13 additions & 1 deletion Auth0/BaseWebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class BaseWebAuth: WebAuthenticatable {
private(set) var organization: String?
private(set) var invitationURL: URL?
private var responseType: [ResponseType] = [.code]
private(set) var additionalHeaders: [String: String] = [:]
private var nonce: String?
private var maxAge: Int?

Expand Down Expand Up @@ -93,6 +94,11 @@ class BaseWebAuth: WebAuthenticatable {
parameters.forEach { self.parameters[$0] = $1 }
return self
}

func additionalHeaders(_ headers: [String: String]) -> Self {
headers.forEach { self.additionalHeaders[$0] = $1 }
return self
}

func responseType(_ responseType: [ResponseType]) -> Self {
self.responseType = responseType
Expand Down Expand Up @@ -283,9 +289,15 @@ class BaseWebAuth: WebAuthenticatable {
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
return components.url!
}

private func urlSessionWithAdditionalHeaders() -> URLSession {
let configurations = URLSessionConfiguration.default
configurations.httpAdditionalHeaders = self.additionalHeaders
return URLSession(configuration: configurations)
}

private func handler(_ redirectURL: URL) -> OAuth2Grant {
var authentication = Auth0Authentication(clientId: self.clientId, url: self.url, telemetry: self.telemetry)
var authentication = Auth0Authentication(clientId: self.clientId, url: self.url, session: urlSessionWithAdditionalHeaders(), telemetry: self.telemetry)
if self.responseType.contains([.code]) { // both Hybrid and Code flow
authentication.logger = self.logger
return PKCE(authentication: authentication,
Expand Down
50 changes: 50 additions & 0 deletions Auth0/CredentialsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,21 @@ public struct CredentialsManager {
self.retrieveCredentials(withScope: scope, minTTL: minTTL, parameters: parameters, callback: callback)
}
}

public func credentials(withScope scope: String? = nil, minTTL: Int = 0, headers: [String: String] = [:], callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
guard self.hasValid(minTTL: minTTL) else { return callback(.noCredentials, nil) }
if #available(iOS 9.0, macOS 10.15, *), let bioAuth = self.bioAuth {
guard bioAuth.available else { return callback(.touchFailed(LAError(LAError.touchIDNotAvailable)), nil) }
bioAuth.validateBiometric {
guard $0 == nil else {
return callback(.touchFailed($0!), nil)
}
self.retrieveCredentials(withScope: scope, minTTL: minTTL, headers: headers, callback: callback)
}
} else {
self.retrieveCredentials(withScope: scope, minTTL: minTTL, headers: headers, callback: callback)
}
}
#else
public func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
guard self.hasValid(minTTL: minTTL) else { return callback(.noCredentials, nil) }
Expand Down Expand Up @@ -233,6 +248,41 @@ public struct CredentialsManager {
}
}
}

private func retrieveCredentials(withScope scope: String?, minTTL: Int, headers: [String: String] = [:], callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
guard let data = self.storage.data(forKey: self.storeKey),
let credentials = NSKeyedUnarchiver.unarchiveObject(with: data) as? Credentials else { return callback(.noCredentials, nil) }
guard let expiresIn = credentials.expiresIn else { return callback(.noCredentials, nil) }
guard self.hasExpired(credentials) ||
self.willExpire(credentials, within: minTTL) ||
self.hasScopeChanged(credentials, from: scope) else { return callback(nil, credentials) }
guard let refreshToken = credentials.refreshToken else { return callback(.noRefreshToken, nil) }

self.authentication.renew(withRefreshToken: refreshToken, scope: scope, headers: headers).start {
switch $0 {
case .success(let credentials):
let newCredentials = Credentials(accessToken: credentials.accessToken,
tokenType: credentials.tokenType,
idToken: credentials.idToken,
refreshToken: credentials.refreshToken ?? refreshToken,
expiresIn: credentials.expiresIn,
scope: credentials.scope)
if self.willExpire(newCredentials, within: minTTL) {
let accessTokenLifetime = Int(expiresIn.timeIntervalSinceNow)
// TODO: On the next major add a new case to CredentialsManagerError
let error = NSError(domain: "The lifetime of the renewed Access Token (\(accessTokenLifetime)s) is less than minTTL requested (\(minTTL)s). Increase the 'Token Expiration' setting of your Auth0 API in the dashboard or request a lower minTTL",
code: -99999,
userInfo: nil)
callback(.failedRefresh(error), nil)
} else {
_ = self.store(credentials: newCredentials)
callback(nil, newCredentials)
}
case .failure(let error):
callback(.failedRefresh(error), nil)
}
}
}

func willExpire(_ credentials: Credentials, within ttl: Int) -> Bool {
if let expiresIn = credentials.expiresIn {
Expand Down
11 changes: 11 additions & 0 deletions Auth0/WebAuthenticatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,5 +266,16 @@ public protocol WebAuthenticatable: Trackable, Loggable {
- parameter callback: callback called with bool outcome of the call
*/
func clearSession(federated: Bool, callback: @escaping (Bool) -> Void)


/**
```
Auth0
.webAuth()
.additionalHeaders(headers: [:])
```
- parameter headers: Headers to add with oAuth/token request
*/
func additionalHeaders(_ headers: [String: String]) -> Self
}
#endif