Skip to content

Commit

Permalink
Added support of JWT tokens. (#104)
Browse files Browse the repository at this point in the history
The type of access token can be changed in the Core.Config class.
  • Loading branch information
volodymyr-chekyrta authored Oct 23, 2023
1 parent c42342e commit 9952bb9
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 45 deletions.
8 changes: 8 additions & 0 deletions Core/Core/Configuration/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class Config {

public let baseURL: URL
public let oAuthClientId: String
public let tokenType: TokenType = .jwt

public lazy var termsOfUse: URL? = {
URL(string: "\(baseURL.description)/tos")
Expand All @@ -31,6 +32,13 @@ public class Config {
}
}

public extension Config {
enum TokenType: String {
case jwt = "JWT"
case bearer = "BEARER"
}
}

// Mark - For testing and SwiftUI preview
#if DEBUG
public class ConfigMock: Config {
Expand Down
3 changes: 2 additions & 1 deletion Core/Core/Data/Repository/AuthRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public class AuthRepository: AuthRepositoryProtocol {
let endPoint = AuthEndpoint.getAccessToken(
username: username,
password: password,
clientId: config.oAuthClientId
clientId: config.oAuthClientId,
tokenType: config.tokenType.rawValue
)
let authResponse = try await api.requestData(endPoint).mapResponse(DataLayer.AuthResponse.self)
guard let accessToken = authResponse.accessToken,
Expand Down
8 changes: 5 additions & 3 deletions Core/Core/Network/AuthEndpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
import Alamofire

enum AuthEndpoint: EndPointType {
case getAccessToken(username: String, password: String, clientId: String)
case getAccessToken(username: String, password: String, clientId: String, tokenType: String)
case getUserInfo
case getAuthCookies
case getRegisterFields
Expand Down Expand Up @@ -61,12 +61,14 @@ enum AuthEndpoint: EndPointType {

var task: HTTPTask {
switch self {
case let .getAccessToken(username, password, clientId):
case let .getAccessToken(username, password, clientId, tokenType):
let params: [String: Encodable] = [
"grant_type": Constants.GrantTypePassword,
"client_id": clientId,
"username": username,
"password": password
"password": password,
"token_type": tokenType,
"asymmetric_jwt": true
]
return .requestParameters(parameters: params, encoding: URLEncoding.httpBody)
case .getUserInfo:
Expand Down
85 changes: 44 additions & 41 deletions Core/Core/Network/RequestInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final public class RequestInterceptor: Alamofire.RequestInterceptor {

// Set the Authorization header value using the access token.
if let token = storage.accessToken {
urlRequest.setValue("Bearer " + token, forHTTPHeaderField: "Authorization")
urlRequest.setValue("\(config.tokenType.rawValue) \(token)", forHTTPHeaderField: "Authorization")
}

completion(.success(urlRequest))
Expand Down Expand Up @@ -84,49 +84,52 @@ final public class RequestInterceptor: Alamofire.RequestInterceptor {

private func refreshToken(
refreshToken: String,
completion: @escaping (_ succeeded: Bool) -> Void) {
guard !isRefreshing else { return }

isRefreshing = true

let url = config.baseURL.appendingPathComponent("/oauth2/access_token")

let parameters = [
"grant_type": Constants.GrantTypeRefreshToken,
"client_id": config.oAuthClientId,
"refresh_token": refreshToken
]
AF.request(
url,
method: .post,
parameters: parameters,
encoding: URLEncoding.httpBody
).response { [weak self] response in
guard let self = self else { return }
switch response.result {
case let .success(data):
do {
let json = try JSONSerialization.jsonObject(
with: data!,
options: .mutableContainers
) as? [String: AnyObject]
guard let json,
let accessToken = json["access_token"] as? String,
let refreshToken = json["refresh_token"] as? String,
accessToken.count > 0,
refreshToken.count > 0 else {
return completion(false)
}
self.storage.accessToken = accessToken
self.storage.refreshToken = refreshToken
completion(true)
} catch {
completion(false)
completion: @escaping (_ succeeded: Bool) -> Void
) {
guard !isRefreshing else { return }

isRefreshing = true

let url = config.baseURL.appendingPathComponent("/oauth2/access_token")

let parameters: [String: Encodable] = [
"grant_type": Constants.GrantTypeRefreshToken,
"client_id": config.oAuthClientId,
"refresh_token": refreshToken,
"token_type": config.tokenType.rawValue,
"asymmetric_jwt": true
]
AF.request(
url,
method: .post,
parameters: parameters,
encoding: URLEncoding.httpBody
).response { [weak self] response in
guard let self = self else { return }
switch response.result {
case let .success(data):
do {
let json = try JSONSerialization.jsonObject(
with: data!,
options: .mutableContainers
) as? [String: AnyObject]
guard let json,
let accessToken = json["access_token"] as? String,
let refreshToken = json["refresh_token"] as? String,
accessToken.count > 0,
refreshToken.count > 0 else {
return completion(false)
}
case .failure:
self.storage.accessToken = accessToken
self.storage.refreshToken = refreshToken
completion(true)
} catch {
completion(false)
}
self.isRefreshing = false
case .failure:
completion(false)
}
self.isRefreshing = false
}
}
}

0 comments on commit 9952bb9

Please sign in to comment.