Skip to content

Commit

Permalink
TokenManager, AccessToken changes
Browse files Browse the repository at this point in the history
  • Loading branch information
mohssenfathi committed May 3, 2024
1 parent 0d3f42b commit 1c373d8
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ fileprivate extension Client {
self = Client(
authorizationCode: nil,
accessToken: AccessToken(
accessToken: tokenResponse.accessToken,
tokenString: tokenResponse.tokenString,
refreshToken: tokenResponse.refreshToken,
tokenType: tokenResponse.tokenType,
expiresIn: tokenResponse.expiresIn,
Expand Down
24 changes: 21 additions & 3 deletions Sources/UberAuth/Button/LoginButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,32 @@ public final class LoginButton: UberButton {
// MARK: Private Properties

private var buttonState: State {
tokenManager.getToken() != nil ? .loggedIn : .loggedOut
tokenManager.getToken(
identifier: Constants.tokenIdentifier
) != nil ? .loggedIn : .loggedOut
}

private let tokenManager = TokenManager()
private let tokenManager: TokenManaging

// MARK: Initializers

public override init(frame: CGRect) {
self.tokenManager = TokenManager()
super.init(frame: frame)
configure()
}

public required init?(coder: NSCoder) {
self.tokenManager = TokenManager()
super.init(coder: coder)
configure()
}

public init(tokenManager: TokenManaging = TokenManager()) {
self.tokenManager = tokenManager
super.init(frame: .zero)
configure()
}

// MARK: UberButton

Expand Down Expand Up @@ -120,10 +130,12 @@ public final class LoginButton: UberButton {

private func logout() {
// TODO: Implement UberAuth.logout()
tokenManager.deleteToken()
tokenManager.deleteToken(identifier: Constants.tokenIdentifier)
update()
}

// MARK: State

enum State {
case loggedIn
case loggedOut
Expand All @@ -147,5 +159,11 @@ public final class LoginButton: UberButton {
}
}
}

// MARK: Constants

private enum Constants {
static let tokenIdentifier: String = TokenManager.defaultAccessTokenIdentifier
}
}

51 changes: 2 additions & 49 deletions Sources/UberAuth/Token/TokenRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


import Foundation

import UberCore

///
/// Defines a network request conforming to the OAuth 2.0 standard access token request
Expand Down Expand Up @@ -40,7 +40,7 @@ struct TokenRequest: NetworkRequest {
.post
}

typealias Response = Token
typealias Response = AccessToken

var parameters: [String : String]? {
[
Expand All @@ -52,50 +52,3 @@ struct TokenRequest: NetworkRequest {
]
}
}

///
/// The Access Token response for the authorization code grant flow as
/// defined by the OAuth 2.0 standard.
/// https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
///
struct Token: Codable {

let accessToken: String
let tokenType: String
let expiresIn: Int?
let refreshToken: String?
let scope: [String]

enum CodingKeys: String, CodingKey {
case accessToken = "access_token"
case tokenType = "token_type"
case expiresIn = "expires_in"
case refreshToken = "refresh_token"
case scope
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.accessToken = try container.decode(String.self, forKey: .accessToken)
self.tokenType = try container.decode(String.self, forKey: .tokenType)
self.expiresIn = try container.decodeIfPresent(Int.self, forKey: .expiresIn)
self.refreshToken = try container.decodeIfPresent(String.self, forKey: .refreshToken)

let scopeString = try container.decodeIfPresent(String.self, forKey: .scope)
self.scope = (scopeString ?? "")
.split(separator: " ")
.map(String.init)
}

init(accessToken: String,
tokenType: String,
expiresIn: Int? = nil,
refreshToken: String? = nil,
scope: [String] = []) {
self.accessToken = accessToken
self.tokenType = tokenType
self.expiresIn = expiresIn
self.refreshToken = refreshToken
self.scope = scope
}
}
42 changes: 38 additions & 4 deletions Sources/UberCore/Authentication/Tokens/AccessToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@

import Foundation

///
/// The Access Token response for the authorization code grant flow as
/// defined by the OAuth 2.0 standard.
/// https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
///
public struct AccessToken: Codable, Equatable {

public let accessToken: String?
public let tokenString: String?

public let refreshToken: String?

Expand All @@ -39,24 +44,53 @@ public struct AccessToken: Codable, Equatable {

// MARK: Initializers

public init(accessToken: String? = nil,
public init(tokenString: String? = nil,
refreshToken: String? = nil,
tokenType: String? = nil,
expiresIn: Int? = nil,
scope: [String]? = nil) {
self.accessToken = accessToken
self.tokenString = tokenString
self.refreshToken = refreshToken
self.tokenType = tokenType
self.expiresIn = expiresIn
self.scope = scope
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let tokenString = try container.decode(String.self, forKey: .tokenString)
let tokenType = try container.decode(String.self, forKey: .tokenType)
let expiresIn = try container.decodeIfPresent(Int.self, forKey: .expiresIn)
let refreshToken = try container.decodeIfPresent(String.self, forKey: .refreshToken)

let scopeString = try container.decodeIfPresent(String.self, forKey: .scope)
let scope = (scopeString ?? "")
.split(separator: " ")
.map(String.init)

self = AccessToken(
tokenString: tokenString,
refreshToken: refreshToken,
tokenType: tokenType,
expiresIn: expiresIn,
scope: scope
)
}

enum CodingKeys: String, CodingKey {
case tokenString = "access_token"
case tokenType = "token_type"
case expiresIn = "expires_in"
case refreshToken = "refresh_token"
case scope
}
}

extension AccessToken: CustomStringConvertible {

public var description: String {
return """
Access Token: \(accessToken ?? "nil")
Token String: \(tokenString ?? "nil")
Refresh Token: \(refreshToken ?? "nil")
Token Type: \(tokenType ?? "nil")
Expires In: \(expiresIn ?? -1)
Expand Down
8 changes: 4 additions & 4 deletions Sources/UberCore/Authentication/Tokens/KeychainUtility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ public protocol KeychainUtilityProtocol {
/// - value: The object to save. Must conform to the Codable protocol.
/// - key: A string value used to identify the saved object
/// - Returns: A boolean indicating whether or not the save operation was successful
func save<V: Codable>(_ value: V, for key: String) -> Bool
func save<V: Encodable>(_ value: V, for key: String) -> Bool

/// Retrieves an object from the on device keychain using the supplied `key`
///
/// - Parameters:
/// - key: The identifier string used when saving the object
/// - Returns: If found, an optional type conforming to the Codable protocol
func get<V: Codable>(key: String) -> V?
func get<V: Decodable>(key: String) -> V?

/// Removes the object from the on device keychain corresponding to the supplied `key`
///
Expand Down Expand Up @@ -76,7 +76,7 @@ public final class KeychainUtility: KeychainUtilityProtocol {
/// - value: The object to save. Must conform to the Codable protocol.
/// - key: A string value used to identify the saved object
/// - Returns: A boolean indicating whether or not the save operation was successful
public func save<V: Codable>(_ value: V, for key: String) -> Bool {
public func save<V: Encodable>(_ value: V, for key: String) -> Bool {
guard let data = try? encoder.encode(value) else {
return false
}
Expand Down Expand Up @@ -108,7 +108,7 @@ public final class KeychainUtility: KeychainUtilityProtocol {
/// - Parameters:
/// - key: The identifier string used when saving the object
/// - Returns: If found, an optional type conforming to the Codable protocol
public func get<V: Codable>(key: String) -> V? {
public func get<V: Decodable>(key: String) -> V? {

var attributes = attributes(for: key)
attributes[Attribute.matchLimit] = kSecMatchLimitOne
Expand Down
1 change: 0 additions & 1 deletion Sources/UberCore/Authentication/Tokens/TokenManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ public final class TokenManager: TokenManaging {
///
/// - Parameter identifier: The identifier string used when saving the Access Token
/// - Returns: An optional Access Token if found
@discardableResult
public func getToken(identifier: String = TokenManager.defaultAccessTokenIdentifier) -> AccessToken? {
keychainUtility.get(key: identifier)
}
Expand Down
4 changes: 2 additions & 2 deletions examples/UberSDK/UberSDKTests/Mocks/Mocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public class KeychainUtilityProtocolMock: KeychainUtilityProtocol {

public private(set) var saveCallCount = 0
public var saveHandler: ((Any, String) -> (Bool))?
public func save<V: Codable>(_ value: V, for key: String) -> Bool {
public func save<V: Encodable>(_ value: V, for key: String) -> Bool {
saveCallCount += 1
if let saveHandler = saveHandler {
return saveHandler(value, key)
Expand All @@ -217,7 +217,7 @@ public class KeychainUtilityProtocolMock: KeychainUtilityProtocol {

public private(set) var getCallCount = 0
public var getHandler: ((String) -> (Any?))?
public func get<V: Codable>(key: String) -> V? {
public func get<V: Decodable>(key: String) -> V? {
getCallCount += 1
if let getHandler = getHandler {
return getHandler(key) as? V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,8 @@ final class AuthorizationCodeAuthProviderTests: XCTestCase {

func test_nativeAuth_tokenExchange() {

let token = Token(
accessToken: "123",
let token = AccessToken(
tokenString: "123",
tokenType: "test_token"
)

Expand Down Expand Up @@ -479,9 +479,8 @@ final class AuthorizationCodeAuthProviderTests: XCTestCase {
client,
Client(
accessToken: AccessToken(
accessToken: "123",
tokenType: "test_token",
scope: []
tokenString: "123",
tokenType: "test_token"
)
)
)
Expand Down
24 changes: 16 additions & 8 deletions examples/UberSDK/UberSDKTests/UberCore/KeychainUtilityTests.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// KeychainUtility.swift
// UberAuth
// UberCore
//
// Copyright © 2024 Uber Technologies, Inc. All rights reserved.
//
Expand Down Expand Up @@ -28,14 +28,26 @@ import XCTest

final class KeychainUtilityTests: XCTestCase {

private let keychainUtility = KeychainUtility()

override func setUp() {
super.setUp()

_ = keychainUtility.delete(key: "test_object")
}

override func tearDown() {
super.tearDown()

_ = keychainUtility.delete(key: "test_object")
}

func test_save() {
let testObject = TestObject(
name: "test",
value: 5
)

let keychainUtility = KeychainUtility()


let saved = keychainUtility.save(testObject, for: "test_object")
XCTAssertTrue(saved)
}
Expand All @@ -46,8 +58,6 @@ final class KeychainUtilityTests: XCTestCase {
value: 5
)

let keychainUtility = KeychainUtility()

_ = keychainUtility.save(testObject, for: "test_object")
let retrievedObject: TestObject? = keychainUtility.get(key: "test_object")

Expand All @@ -60,8 +70,6 @@ final class KeychainUtilityTests: XCTestCase {
value: 5
)

let keychainUtility = KeychainUtility()

_ = keychainUtility.save(testObject, for: "test_object")
let deleted = keychainUtility.delete(key: "test_object")
XCTAssertTrue(deleted)
Expand Down
Loading

0 comments on commit 1c373d8

Please sign in to comment.