-
Notifications
You must be signed in to change notification settings - Fork 12
Adds mobile token has auth header #96
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,11 @@ | |
|
|
||
| import Foundation | ||
|
|
||
| /// Closure supplied by the App, which is responsible for returning a fresh mobile token from the server. | ||
| /// The SDK invokes it during configure and whenever a request fails with a 401. The Server must mint a token via | ||
| /// `create_mobile_token` and return the raw token to the App. | ||
| public typealias CBMobileTokenProvider = (@escaping (String?) -> Void) -> Void | ||
|
|
||
| class CBEnvironment { | ||
| static var site: String = "" | ||
| static var apiKey: String = "" | ||
|
|
@@ -14,7 +19,13 @@ class CBEnvironment { | |
| static var version: CatalogVersion = .unknown | ||
| static var session = URLSession.shared | ||
| static var environment: String = "cb_ios_sdk" | ||
|
|
||
| // When a mobile token is present, the SDK sends it for the `Authorization` similar to the publishable key. | ||
| // If empty, we fall back to the publishable key flow. | ||
| static var mobileToken: String = "" | ||
| static var tokenProvider: CBMobileTokenProvider? | ||
| static var encodedMobileToken: String { | ||
| return mobileToken.data(using: .utf8)?.base64EncodedString() ?? "" | ||
| } | ||
|
|
||
| func configure(site: String, apiKey: String, allowErrorLogging: Bool, sdkKey: String? = nil) { | ||
| let resultHandler: CBAuthenticationHandler = { result in | ||
|
|
@@ -65,4 +76,55 @@ class CBEnvironment { | |
| } | ||
| } | ||
|
|
||
| // Mobile token flow: the SDK is configured without a publishable key. We fetch a token from | ||
| // the App's token provider and then verify the app details using it. If successful, the SDK is ready to use. | ||
| func configure(site: String, sdkKey: String? = nil, allowErrorLogging: Bool, tokenProvider: @escaping CBMobileTokenProvider, handler: @escaping CBAuthenticationHandler) { | ||
| CBEnvironment.site = site | ||
| CBEnvironment.apiKey = "" | ||
| CBEnvironment.encodedApiKey = "" | ||
| CBEnvironment.allowErrorLogging = allowErrorLogging | ||
| CBEnvironment.baseUrl = "https://\(site).chargebee.com/api" | ||
| CBEnvironment.version = .unknown | ||
| CBEnvironment.tokenProvider = tokenProvider | ||
| if let sdkKey = sdkKey { | ||
| CBEnvironment.sdkKey = sdkKey | ||
| } | ||
|
|
||
| let (onSuccess, onError) = CBResult.buildResultHandlers(handler, nil) | ||
| CBEnvironment.refreshMobileToken { success in | ||
| guard success else { | ||
| return onError(CBError.defaultSytemError(statusCode: 401, message: "Unable to fetch a mobile token from the token provider")) | ||
| } | ||
| guard CBEnvironment.sdkKey.isNotEmpty else { | ||
| // Nothing to verify without an SDK key; environment is ready. | ||
| return onSuccess(CBAuthenticationStatus(details: CBAuthentication(appId: nil, status: "ok", version: .unknown))) | ||
| } | ||
| CBAuthenticationManager().authenticate(forSDKKey: CBEnvironment.sdkKey) { result in | ||
| switch result { | ||
| case .success(let status): | ||
| CBEnvironment.version = status.details.version ?? .unknown | ||
| onSuccess(status) | ||
| case .error(let error): | ||
| CBEnvironment.version = .unknown | ||
| onError(error) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Fetches a fresh token from the App's token provider and stores it. | ||
| static func refreshMobileToken(completion: @escaping (Bool) -> Void) { | ||
| guard let provider = tokenProvider else { | ||
| return completion(false) | ||
| } | ||
| provider { token in | ||
| if let token = token, token.isNotEmpty { | ||
| CBEnvironment.mobileToken = token | ||
| completion(true) | ||
|
Comment on lines
+116
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Synchronize mobile-token state. The token-provider callback writes As per path instructions, “focus strictly on merge-blocking concerns.” 🤖 Prompt for AI AgentsSource: Path instructions |
||
| } else { | ||
| completion(false) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Reset authentication state on reconfiguration.
If this overload receives
sdkKey: nil, it retains a previousCBEnvironment.sdkKey. If API-key configuration follows mobile-token configuration,mobileTokenandtokenProviderremain set, soresolvedAuthHeaderstill selects the old mobile token. AssignsdkKey = sdkKey ?? ""here, and clear mobile-token state in the API-key configuration path.As per path instructions, “focus solely on correctness and safety.”
🤖 Prompt for AI Agents
Source: Path instructions