SecureTokenRequest.swift 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright 2023 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. enum SecureTokenRequestGrantType: Int {
  16. case authorizationCode
  17. case refreshToken
  18. var value: String {
  19. switch self {
  20. case .refreshToken:
  21. return kFIRSecureTokenServiceGrantTypeRefreshToken
  22. case .authorizationCode:
  23. return kFIRSecureTokenServiceGrantTypeAuthorizationCode
  24. }
  25. }
  26. }
  27. /** @var kFIRSecureTokenServiceGetTokenURLFormat
  28. @brief The format of the secure token service URLs. Requires string format substitution with
  29. the client's API Key.
  30. */
  31. private let kFIRSecureTokenServiceGetTokenURLFormat = "https://%@/v1/token?key=%@"
  32. /** @var kFIREmulatorURLFormat
  33. @brief The format of the emulated secure token service URLs. Requires string format substitution
  34. with the emulator host, the gAPIHost, and the client's API Key.
  35. */
  36. private let kFIREmulatorURLFormat = "http://%@/%@/v1/token?key=%@"
  37. /** @var kFIRSecureTokenServiceGrantTypeRefreshToken
  38. @brief The string value of the @c FIRSecureTokenRequestGrantTypeRefreshToken request type.
  39. */
  40. private let kFIRSecureTokenServiceGrantTypeRefreshToken = "refresh_token"
  41. /** @var kFIRSecureTokenServiceGrantTypeAuthorizationCode
  42. @brief The string value of the @c FIRSecureTokenRequestGrantTypeAuthorizationCode request type.
  43. */
  44. private let kFIRSecureTokenServiceGrantTypeAuthorizationCode = "authorization_code"
  45. /** @var kGrantTypeKey
  46. @brief The key for the "grantType" parameter in the request.
  47. */
  48. private let kGrantTypeKey = "grantType"
  49. /** @var kScopeKey
  50. @brief The key for the "scope" parameter in the request.
  51. */
  52. private let kScopeKey = "scope"
  53. /** @var kRefreshTokenKey
  54. @brief The key for the "refreshToken" parameter in the request.
  55. */
  56. private let kRefreshTokenKey = "refreshToken"
  57. /** @var kCodeKey
  58. @brief The key for the "code" parameter in the request.
  59. */
  60. private let kCodeKey = "code"
  61. /** @var gAPIHost
  62. @brief Host for server API calls.
  63. */
  64. private var gAPIHost = "securetoken.googleapis.com"
  65. /** @class FIRSecureTokenRequest
  66. @brief Represents the parameters for the token endpoint.
  67. */
  68. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  69. class SecureTokenRequest: AuthRPCRequest {
  70. typealias Response = SecureTokenResponse
  71. /** @property grantType
  72. @brief The type of grant requested.
  73. @see FIRSecureTokenRequestGrantType
  74. */
  75. var grantType: SecureTokenRequestGrantType
  76. /** @property scope
  77. @brief The scopes requested (a comma-delimited list of scope strings.)
  78. */
  79. var scope: String?
  80. /** @property refreshToken
  81. @brief The client's refresh token.
  82. */
  83. var refreshToken: String?
  84. /** @property code
  85. @brief The client's authorization code (legacy Gitkit "ID Token").
  86. */
  87. var code: String?
  88. /** @property APIKey
  89. @brief The client's API Key.
  90. */
  91. let apiKey: String
  92. let _requestConfiguration: AuthRequestConfiguration
  93. func requestConfiguration() -> AuthRequestConfiguration {
  94. _requestConfiguration
  95. }
  96. static func authCodeRequest(code: String,
  97. requestConfiguration: AuthRequestConfiguration)
  98. -> SecureTokenRequest {
  99. SecureTokenRequest(
  100. grantType: .authorizationCode,
  101. scope: nil,
  102. refreshToken: nil,
  103. code: code,
  104. requestConfiguration: requestConfiguration
  105. )
  106. }
  107. static func refreshRequest(refreshToken: String,
  108. requestConfiguration: AuthRequestConfiguration)
  109. -> SecureTokenRequest {
  110. SecureTokenRequest(
  111. grantType: .refreshToken,
  112. scope: nil,
  113. refreshToken: refreshToken,
  114. code: nil,
  115. requestConfiguration: requestConfiguration
  116. )
  117. }
  118. init(grantType: SecureTokenRequestGrantType, scope: String?, refreshToken: String?,
  119. code: String?, requestConfiguration: AuthRequestConfiguration) {
  120. self.grantType = grantType
  121. self.scope = scope
  122. self.refreshToken = refreshToken
  123. self.code = code
  124. apiKey = requestConfiguration.apiKey
  125. _requestConfiguration = requestConfiguration
  126. }
  127. func requestURL() -> URL {
  128. let urlString: String
  129. if let emulatorHostAndPort = _requestConfiguration.emulatorHostAndPort {
  130. urlString = "http://\(emulatorHostAndPort)/\(gAPIHost)/v1/token?key=\(apiKey)"
  131. } else {
  132. urlString = "https://\(gAPIHost)/v1/token?key=\(apiKey)"
  133. }
  134. return URL(string: urlString)!
  135. }
  136. func containsPostBody() -> Bool { true }
  137. func unencodedHTTPRequestBody() throws -> [String: AnyHashable] {
  138. var postBody: [String: AnyHashable] = [
  139. kGrantTypeKey: grantType.value,
  140. ]
  141. if let scope = scope {
  142. postBody[kScopeKey] = scope
  143. }
  144. if let refreshToken = refreshToken {
  145. postBody[kRefreshTokenKey] = refreshToken
  146. }
  147. if let code = code {
  148. postBody[kCodeKey] = code
  149. }
  150. return postBody
  151. }
  152. // MARK: Internal API for development
  153. static var host: String { gAPIHost }
  154. static func setHost(_ host: String) {
  155. gAPIHost = host
  156. }
  157. }