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

Add support for custom URL sessions to Web Auth [SDK-2906] #556

Merged
merged 1 commit into from
Nov 30, 2021
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
8 changes: 4 additions & 4 deletions Auth0/Auth0.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public let defaultScope = "openid profile email"

- parameter clientId: clientId of your Auth0 application
- parameter domain: domain of your Auth0 account. e.g.: 'samples.auth0.com'
- parameter session: instance of NSURLSession used for networking. By default it will use the shared NSURLSession
- parameter session: instance of URLSession used for networking. By default it will use the shared URLSession

- returns: Auth0 Authentication API
*/
Expand Down Expand Up @@ -49,7 +49,7 @@ public func authentication(clientId: String, domain: String, session: URLSession
</plist>
```

- parameter session: instance of NSURLSession used for networking. By default it will use the shared NSURLSession
- parameter session: instance of URLSession used for networking. By default it will use the shared URLSession
- parameter bundle: bundle used to locate the `Auth0.plist` file. By default is the main bundle

- returns: Auth0 Authentication API
Expand Down Expand Up @@ -90,7 +90,7 @@ public func authentication(session: URLSession = .shared, bundle: Bundle = .main
```

- parameter token: token of Management API v2 with the correct allowed scopes to perform the desired action
- parameter session: instance of NSURLSession used for networking. By default it will use the shared NSURLSession
- parameter session: instance of URLSession used for networking. By default it will use the shared URLSession
- parameter bundle: bundle used to locate the `Auth0.plist` file. By default is the main bundle

- returns: Auth0 Management API v2
Expand All @@ -117,7 +117,7 @@ public func users(token: String, session: URLSession = .shared, bundle: Bundle =

- parameter token: token of Management API v2 with the correct allowed scopes to perform the desired action
- parameter domain: domain of your Auth0 account. e.g.: 'samples.auth0.com'
- parameter session: instance of NSURLSession used for networking. By default it will use the shared NSURLSession
- parameter session: instance of URLSession used for networking. By default it will use the shared URLSession

- returns: Auth0 Management API v2
*/
Expand Down
41 changes: 24 additions & 17 deletions Auth0/Auth0WebAuth.swift
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
#if WEB_AUTH_PLATFORM
import AuthenticationServices
import Foundation

final class Auth0WebAuth: WebAuth {

let clientId: String
let url: URL
let session: URLSession
let storage: TransactionStore

var telemetry: Telemetry
var logger: Logger?
var ephemeralSession = false

#if os(macOS)
private let platform = "macos"
#else
private let platform = "ios"
#endif

private let responseType = "code"
private let requiredScope = "openid"

private(set) var parameters: [String: String] = [:]
private(set) var ephemeralSession = false
private(set) var issuer: String
private(set) var leeway: Int = 60 * 1000 // Default leeway is 60 seconds
private(set) var nonce: String?
private(set) var maxAge: Int?
private(set) var organization: String?
private(set) var invitationURL: URL?
private var nonce: String?
private var maxAge: Int?

lazy var redirectURL: URL? = {
guard let bundleIdentifier = Bundle.main.bundleIdentifier else { return nil }
Expand All @@ -38,10 +40,12 @@ final class Auth0WebAuth: WebAuth {

init(clientId: String,
url: URL,
session: URLSession = URLSession.shared,
storage: TransactionStore = TransactionStore.shared,
telemetry: Telemetry = Telemetry()) {
self.clientId = clientId
self.url = url
self.session = session
self.storage = storage
self.telemetry = telemetry
self.issuer = "\(url.absoluteString)/"
Expand Down Expand Up @@ -207,18 +211,6 @@ final class Auth0WebAuth: WebAuth {
return components.url!
}

private func handler(_ redirectURL: URL) -> OAuth2Grant {
var authentication = Auth0Authentication(clientId: self.clientId, url: self.url, telemetry: self.telemetry)
authentication.logger = self.logger
return PKCE(authentication: authentication,
redirectURL: redirectURL,
issuer: self.issuer,
leeway: self.leeway,
maxAge: self.maxAge,
nonce: self.nonce,
organization: self.organization)
}

func generateDefaultState() -> String? {
let data = Data(count: 32)
var tempData = data
Expand All @@ -231,6 +223,21 @@ final class Auth0WebAuth: WebAuth {
return tempData.a0_encodeBase64URLSafe()
}

private func handler(_ redirectURL: URL) -> OAuth2Grant {
var authentication = Auth0Authentication(clientId: self.clientId,
url: self.url,
session: self.session,
telemetry: self.telemetry)
authentication.logger = self.logger
return PKCE(authentication: authentication,
redirectURL: redirectURL,
issuer: self.issuer,
leeway: self.leeway,
maxAge: self.maxAge,
nonce: self.nonce,
organization: self.organization)
}

}

extension Auth0Authentication {
Expand Down
2 changes: 1 addition & 1 deletion Auth0/AuthenticationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ extension AuthenticationError: CustomDebugStringConvertible {
extension AuthenticationError {

/**
Returns a value from the error's `info` dictionary
Returns a value from the error data

- parameter key: key of the value to return

Expand Down
1 change: 0 additions & 1 deletion Auth0/JWK+RSA.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#if WEB_AUTH_PLATFORM
import Foundation
import SimpleKeychain

extension JWK {
var rsaPublicKey: SecKey? {
Expand Down
2 changes: 1 addition & 1 deletion Auth0/ManagementError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ extension ManagementError: CustomDebugStringConvertible {
extension ManagementError {

/**
Returns a value from the error's `info` dictionary
Returns a value from the error data

- parameter key: key of the value to return

Expand Down
1 change: 0 additions & 1 deletion Auth0/OAuth2Grant.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import JWTDecode

protocol OAuth2Grant {
var defaults: [String: String] { get }
Expand Down
10 changes: 6 additions & 4 deletions Auth0/WebAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import Foundation
</plist>
```

- parameter session: instance of URLSession used for networking. By default it will use the shared URLSession
- parameter bundle: bundle used to locate the `Auth0.plist` file. By default is the main bundle

- returns: Auth0 WebAuth component
- important: Calling this method without a valid `Auth0.plist` will crash your application
*/
public func webAuth(bundle: Bundle = Bundle.main) -> WebAuth {
public func webAuth(session: URLSession = .shared, bundle: Bundle = Bundle.main) -> WebAuth {
let values = plistValues(bundle: bundle)!
return webAuth(clientId: values.clientId, domain: values.domain)
return webAuth(clientId: values.clientId, domain: values.domain, session: session)
}

/**
Expand All @@ -42,11 +43,12 @@ public func webAuth(bundle: Bundle = Bundle.main) -> WebAuth {

- parameter clientId: Id of your Auth0 client
- parameter domain: name of your Auth0 domain
- parameter session: instance of URLSession used for networking. By default it will use the shared URLSession

- returns: Auth0 WebAuth component
*/
public func webAuth(clientId: String, domain: String) -> WebAuth {
return Auth0WebAuth(clientId: clientId, url: .a0_url(domain))
public func webAuth(clientId: String, domain: String, session: URLSession = .shared) -> WebAuth {
return Auth0WebAuth(clientId: clientId, url: .a0_url(domain), session: session)
}

/// WebAuth Authentication using Auth0
Expand Down
27 changes: 26 additions & 1 deletion Auth0Tests/AuthenticationSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import OHHTTPStubsSwift

private let ClientId = "CLIENT_ID"
private let Domain = "samples.auth0.com"
private let DomainURL = URL(string: "https://\(Domain)")!

private let Phone = "+144444444444"
private let ValidPassword = "I.O.U. a password"
Expand All @@ -26,7 +27,7 @@ private let PasswordlessGrantType = "http://auth0.com/oauth/grant-type/passwordl
class AuthenticationSpec: QuickSpec {
override func spec() {

let auth: Authentication = Auth0Authentication(clientId: ClientId, url: URL(string: "https://\(Domain)")!)
let auth: Authentication = Auth0Authentication(clientId: ClientId, url: DomainURL)

beforeEach {
stub(condition: isHost(Domain)) { _ in
Expand All @@ -38,6 +39,30 @@ class AuthenticationSpec: QuickSpec {
HTTPStubs.removeAllStubs()
}

describe("init") {

it("should init with client id & url") {
let authentication = Auth0Authentication(clientId: ClientId, url: DomainURL)
expect(authentication.clientId) == ClientId
expect(authentication.url) == DomainURL
}

it("should init with client id, url & session") {
let session = URLSession(configuration: URLSession.shared.configuration)
let authentication = Auth0Authentication(clientId: ClientId, url: DomainURL, session: session)
expect(authentication.session).to(be(session))
}

it("should init with client id, url & telemetry") {
let telemetryInfo = "info"
var telemetry = Telemetry()
telemetry.info = telemetryInfo
let authentication = Auth0Authentication(clientId: ClientId, url: DomainURL, telemetry: telemetry)
expect(authentication.telemetry.info) == telemetryInfo
}

}

describe("login MFA OTP") {

beforeEach {
Expand Down
17 changes: 14 additions & 3 deletions Auth0Tests/ManagementSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,29 @@ class ManagementSpec: QuickSpec {

it("should init with token & url") {
let management = Management(token: Token, url: DomainURL)
expect(management).toNot(beNil())
expect(management.token) == Token
expect(management.url) == DomainURL
}

it("should init with token, url & session") {
let management = Management(token: Token, url: DomainURL, session: URLSession.shared)
expect(management).toNot(beNil())
let session = URLSession(configuration: URLSession.shared.configuration)
let management = Management(token: Token, url: DomainURL, session: session)
expect(management.session).to(be(session))
}

it("should init with token, url & telemetry") {
let telemetryInfo = "info"
var telemetry = Telemetry()
telemetry.info = telemetryInfo
let management = Management(token: Token, url: DomainURL, telemetry: telemetry)
expect(management.telemetry.info) == telemetryInfo
}

it("should have bearer token in authorization header") {
let management = Management(token: Token, url: DomainURL)
expect(management.defaultHeaders["Authorization"]) == "Bearer \(Token)"
}

}

describe("object response handling") {
Expand Down
30 changes: 30 additions & 0 deletions Auth0Tests/WebAuthSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,36 @@ class WebAuthSpec: QuickSpec {

override func spec() {

describe("init") {

it("should init with client id & url") {
let webAuth = Auth0WebAuth(clientId: ClientId, url: DomainURL)
expect(webAuth.clientId) == ClientId
expect(webAuth.url) == DomainURL
}

it("should init with client id, url & session") {
let session = URLSession(configuration: URLSession.shared.configuration)
let webAuth = Auth0WebAuth(clientId: ClientId, url: DomainURL, session: session)
expect(webAuth.session).to(be(session))
}

it("should init with client id, url & storage") {
let storage = TransactionStore()
let webAuth = Auth0WebAuth(clientId: ClientId, url: DomainURL, storage: storage)
expect(webAuth.storage).to(be(storage))
}

it("should init with client id, url & telemetry") {
let telemetryInfo = "info"
var telemetry = Telemetry()
telemetry.info = telemetryInfo
let webAuth = Auth0WebAuth(clientId: ClientId, url: DomainURL, telemetry: telemetry)
expect(webAuth.telemetry.info) == telemetryInfo
}

}

describe("authorize URL") {

itBehavesLike(ValidAuthorizeURLExample) {
Expand Down
2 changes: 1 addition & 1 deletion V2_MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ switch error {
switch error {
case .revokeFailed: handleError(error.cause) // handle underlying error
// ...
default: // handle unkwown errors, e.g. errors added in future versions
default: // handle unknown errors, e.g. errors added in future versions
}
```

Expand Down