Skip to content

Commit a69f21d

Browse files
kmeinhWidcket
andauthored
Add parameter option to Request (#494)
* Make `Request.payload` modifiable * Add `parameter` to `credentials` in `CredentialsManager` * rename `parameter` -> `parameters` * use spaces instead of tabs for formatting * add Comments for parameters * use spaces on comment * rename `payload` to `parameters` * add tests to read and modify payload on renew * update override Test * add test to verify that copied object contains the same information * Fix several typos and improve API readability * Add test to check if parameters are passed through the HTTP-layer * Update Auth0/CredentialsManager.swift * Update Auth0Tests/CredentialsManagerSpec.swift * Update Auth0/Request.swift Co-authored-by: Rita Zerrizuela <[email protected]>
1 parent 8e8a6b0 commit a69f21d

File tree

4 files changed

+103
-32
lines changed

4 files changed

+103
-32
lines changed

Auth0/CredentialsManager.swift

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -164,70 +164,74 @@ public struct CredentialsManager {
164164
/// - Parameters:
165165
/// - scope: scopes to request for the new tokens. By default is nil which will ask for the same ones requested during original Auth.
166166
/// - minTTL: minimum time in seconds the access token must remain valid to avoid being renewed.
167+
/// - parameters: additional parameters to add to a possible token refresh. The parameters will be set via Request.payload.
167168
/// - callback: callback with the user's credentials or the cause of the error.
168169
/// - Important: This method only works for a refresh token obtained after auth with OAuth 2.0 API Authorization.
169170
/// - Note: [Auth0 Refresh Tokens Docs](https://auth0.com/docs/tokens/concepts/refresh-tokens)
170171
#if WEB_AUTH_PLATFORM
171-
public func credentials(withScope scope: String? = nil, minTTL: Int = 0, callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
172+
public func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
172173
guard self.hasValid(minTTL: minTTL) else { return callback(.noCredentials, nil) }
173174
if #available(iOS 9.0, macOS 10.15, *), let bioAuth = self.bioAuth {
174175
guard bioAuth.available else { return callback(.touchFailed(LAError(LAError.touchIDNotAvailable)), nil) }
175176
bioAuth.validateBiometric {
176177
guard $0 == nil else {
177178
return callback(.touchFailed($0!), nil)
178179
}
179-
self.retrieveCredentials(withScope: scope, minTTL: minTTL, callback: callback)
180+
self.retrieveCredentials(withScope: scope, minTTL: minTTL, parameters: parameters, callback: callback)
180181
}
181182
} else {
182-
self.retrieveCredentials(withScope: scope, minTTL: minTTL, callback: callback)
183+
self.retrieveCredentials(withScope: scope, minTTL: minTTL, parameters: parameters, callback: callback)
183184
}
184185
}
185186
#else
186-
public func credentials(withScope scope: String? = nil, minTTL: Int = 0, callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
187+
public func credentials(withScope scope: String? = nil, minTTL: Int = 0, parameters: [String: Any] = [:], callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
187188
guard self.hasValid(minTTL: minTTL) else { return callback(.noCredentials, nil) }
188-
self.retrieveCredentials(withScope: scope, minTTL: minTTL, callback: callback)
189+
self.retrieveCredentials(withScope: scope, minTTL: minTTL, parameters: parameters, callback: callback)
189190
}
190191
#endif
191192

192193
private func retrieveCredentials() -> Credentials? {
193194
guard let data = self.storage.data(forKey: self.storeKey),
194-
let credentials = NSKeyedUnarchiver.unarchiveObject(with: data) as? Credentials else { return nil }
195+
let credentials = NSKeyedUnarchiver.unarchiveObject(with: data) as? Credentials else { return nil }
195196

196197
return credentials
197198
}
198199

199-
private func retrieveCredentials(withScope scope: String?, minTTL: Int, callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
200+
private func retrieveCredentials(withScope scope: String?, minTTL: Int, parameters: [String: Any] = [:], callback: @escaping (CredentialsManagerError?, Credentials?) -> Void) {
200201
guard let credentials = retrieveCredentials(),
201-
let expiresIn = credentials.expiresIn else { return callback(.noCredentials, nil) }
202+
let expiresIn = credentials.expiresIn else { return callback(.noCredentials, nil) }
202203
guard self.hasExpired(credentials) ||
203-
self.willExpire(credentials, within: minTTL) ||
204-
self.hasScopeChanged(credentials, from: scope) else { return callback(nil, credentials) }
204+
self.willExpire(credentials, within: minTTL) ||
205+
self.hasScopeChanged(credentials, from: scope) else { return callback(nil, credentials) }
205206
guard let refreshToken = credentials.refreshToken else { return callback(.noRefreshToken, nil) }
206207

207-
self.authentication.renew(withRefreshToken: refreshToken, scope: scope).start {
208-
switch $0 {
209-
case .success(let credentials):
210-
let newCredentials = Credentials(accessToken: credentials.accessToken,
211-
tokenType: credentials.tokenType,
212-
idToken: credentials.idToken,
213-
refreshToken: credentials.refreshToken ?? refreshToken,
214-
expiresIn: credentials.expiresIn,
215-
scope: credentials.scope)
216-
if self.willExpire(newCredentials, within: minTTL) {
217-
let accessTokenLifetime = Int(expiresIn.timeIntervalSinceNow)
218-
// TODO: On the next major add a new case to CredentialsManagerError
219-
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",
220-
code: -99999,
221-
userInfo: nil)
208+
self.authentication
209+
.renew(withRefreshToken: refreshToken, scope: scope)
210+
.parameters(parameters)
211+
.start {
212+
switch $0 {
213+
case .success(let credentials):
214+
let newCredentials = Credentials(accessToken: credentials.accessToken,
215+
tokenType: credentials.tokenType,
216+
idToken: credentials.idToken,
217+
refreshToken: credentials.refreshToken ?? refreshToken,
218+
expiresIn: credentials.expiresIn,
219+
scope: credentials.scope)
220+
if self.willExpire(newCredentials, within: minTTL) {
221+
let accessTokenLifetime = Int(expiresIn.timeIntervalSinceNow)
222+
// TODO: On the next major add a new case to CredentialsManagerError
223+
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",
224+
code: -99999,
225+
userInfo: nil)
226+
callback(.failedRefresh(error), nil)
227+
} else {
228+
_ = self.store(credentials: newCredentials)
229+
callback(nil, newCredentials)
230+
}
231+
case .failure(let error):
222232
callback(.failedRefresh(error), nil)
223-
} else {
224-
_ = self.store(credentials: newCredentials)
225-
callback(nil, newCredentials)
226233
}
227-
case .failure(let error):
228-
callback(.failedRefresh(error), nil)
229234
}
230-
}
231235
}
232236

233237
func willExpire(_ credentials: Credentials, within ttl: Int) -> Bool {

Auth0/Request.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ public struct Request<T, E: Auth0Error>: Requestable {
9595
task.resume()
9696
}
9797

98+
/**
99+
Modify the parameters by creating a copy of self and adding the provided parameters to `payload`.
100+
101+
- parameter payload: Additional parameters for the request. The provided map will be added to `payload`.
102+
*/
103+
public func parameters(_ payload: [String: Any]) -> Self {
104+
var parameter = self.payload
105+
payload.forEach { parameter[$0] = $1 }
106+
107+
return Request(session: self.session, url: self.url, method: self.method, handle: self.handle, payload: parameter, headers: self.headers, logger: self.logger, telemetry: self.telemetry)
108+
}
98109
}
99110

100111
/**

Auth0Tests/AuthenticationSpec.swift

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,46 @@ class AuthenticationSpec: QuickSpec {
318318
}
319319

320320
}
321-
321+
322+
// MARK:- Modify and Create Requests
323+
324+
describe("Requests create and update") {
325+
326+
let refreshToken = UUID().uuidString.replacingOccurrences(of: "-", with: "")
327+
328+
it("should contain payload") {
329+
let request = auth.renew(withRefreshToken: refreshToken)
330+
331+
expect(request.payload["refresh_token"] as? String) == refreshToken
332+
expect(request.payload["grant_type"] as? String) == "refresh_token"
333+
expect(request.payload["client_id"] as? String) == ClientId
334+
}
335+
336+
it("add and override parameters") {
337+
let request = auth.renew(withRefreshToken: refreshToken)
338+
.parameters([
339+
"client_id": "new Client ID",
340+
"phone": Phone
341+
])
342+
343+
expect(request.payload["refresh_token"] as? String) == refreshToken
344+
expect(request.payload["grant_type"] as? String) == "refresh_token"
345+
expect(request.payload["client_id"] as? String) == "new Client ID"
346+
expect(request.payload["phone"] as? String) == Phone
347+
}
348+
349+
it("copy contains same informations") {
350+
let baseRequest = auth.renew(withRefreshToken: refreshToken)
351+
let modifiedRequest = baseRequest.parameters([:])
352+
353+
expect(baseRequest.session) == modifiedRequest.session
354+
expect(baseRequest.url) == modifiedRequest.url
355+
expect(baseRequest.method) == modifiedRequest.method
356+
expect(baseRequest.payload as? [String: String]) == modifiedRequest.payload as? [String: String]
357+
expect(baseRequest.headers) == modifiedRequest.headers
358+
}
359+
}
360+
322361
// MARK:- Token Exchange
323362

324363
describe("native social token exchange") {

Auth0Tests/CredentialsManagerSpec.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,23 @@ class CredentialsManagerSpec: QuickSpec {
530530
}
531531
}
532532

533+
it("request should include custom parameters on renew") {
534+
let someId = UUID().uuidString
535+
stub(condition: isToken(Domain) && hasAtLeast(["refresh_token": RefreshToken, "some_id": someId])) {
536+
_ in return authResponse(accessToken: NewAccessToken, idToken: NewIdToken, refreshToken: NewRefreshToken, expiresIn: 86400)
537+
}
538+
credentials = Credentials(accessToken: AccessToken, tokenType: TokenType, idToken: IdToken, refreshToken: RefreshToken, expiresIn: Date(timeIntervalSinceNow: -3600))
539+
_ = credentialsManager.store(credentials: credentials)
540+
waitUntil(timeout: Timeout) { done in
541+
credentialsManager.credentials(parameters: ["some_id": someId]) { error = $0; newCredentials = $1
542+
expect(error).to(beNil())
543+
expect(newCredentials?.accessToken) == NewAccessToken
544+
expect(newCredentials?.refreshToken) == NewRefreshToken
545+
expect(newCredentials?.idToken) == NewIdToken
546+
done()
547+
}
548+
}
549+
}
533550
}
534551

535552
context("forced renew") {

0 commit comments

Comments
 (0)