| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- // Copyright 2023 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- import Foundation
- /** @var kExpirationDateKey
- @brief The key used to encode the expirationDate property for NSSecureCoding.
- */
- // XXX TODO: TYPO IN ORIGINAL KEY. TO FIX OR NOT?
- private let kExpirationDateKey = "expiratinDate"
- /** @var kTokenKey
- @brief The key used to encode the token property for NSSecureCoding.
- */
- private let kTokenKey = "token"
- /** @var kAuthDateKey
- @brief The key used to encode the authDate property for NSSecureCoding.
- */
- private let kAuthDateKey = "authDate"
- /** @var kIssuedDateKey
- @brief The key used to encode the issuedDate property for NSSecureCoding.
- */
- private let kIssuedDateKey = "issuedDate"
- /** @var kSignInProviderKey
- @brief The key used to encode the signInProvider property for NSSecureCoding.
- */
- private let kSignInProviderKey = "signInProvider"
- /** @var kSignInSecondFactorKey
- @brief The key used to encode the signInSecondFactor property for NSSecureCoding.
- */
- private let kSignInSecondFactorKey = "signInSecondFactor"
- /** @var kClaimsKey
- @brief The key used to encode the claims property for NSSecureCoding.
- */
- private let kClaimsKey = "claims"
- /** @class FIRAuthTokenResult
- @brief A data class containing the ID token JWT string and other properties associated with the
- token including the decoded payload claims.
- */
- @objc(FIRAuthTokenResult) public class AuthTokenResult: NSObject {
- /** @property token
- @brief Stores the JWT string of the ID token.
- */
- @objc public var token: String
- /** @property expirationDate
- @brief Stores the ID token's expiration date.
- */
- @objc public var expirationDate: Date
- /** @property authDate
- @brief Stores the ID token's authentication date.
- @remarks This is the date the user was signed in and NOT the date the token was refreshed.
- */
- @objc public var authDate: Date
- /** @property issuedAtDate
- @brief Stores the date that the ID token was issued.
- @remarks This is the date last refreshed and NOT the last authentication date.
- */
- @objc public var issuedAtDate: Date
- /** @property signInProvider
- @brief Stores sign-in provider through which the token was obtained.
- @remarks This does not necessarily map to provider IDs.
- */
- @objc public var signInProvider: String
- /** @property signInSecondFactor
- @brief Stores sign-in second factor through which the token was obtained.
- */
- @objc public var signInSecondFactor: String?
- /** @property claims
- @brief Stores the entire payload of claims found on the ID token. This includes the standard
- reserved claims as well as custom claims set by the developer via the Admin SDK.
- */
- @objc public var claims: [String: Any]
- /** @fn tokenResultWithToken:
- @brief Parse a token string to a structured token.
- @param token The token string to parse.
- @return A structured token result.
- */
- @objc public class func tokenResult(token: String) -> AuthTokenResult? {
- let tokenStringArray = token.components(separatedBy: ".")
- // The JWT should have three parts, though we only use the second in this method.
- if tokenStringArray.count != 3 {
- return nil
- }
- // The token payload is always the second index of the array.
- let IDToken = tokenStringArray[1]
- // Convert the base64URL encoded string to a base64 encoded string.
- // Replace "_" with "/"
- // Replace "-" with "+"
- var tokenPayload = IDToken.replacingOccurrences(of: "_", with: "/")
- .replacingOccurrences(of: "-", with: "+")
- // Pad the token payload with "=" signs if the payload's length is not a multiple of 4.
- if tokenPayload.count % 4 != 0 {
- let length = tokenPayload.count + (4 - tokenPayload.count % 4)
- tokenPayload = tokenPayload.padding(toLength: length, withPad: "=", startingAt: 0)
- }
- guard let decodedTokenPayloadData = Data(
- base64Encoded: tokenPayload,
- options: [.ignoreUnknownCharacters]
- ) else {
- return nil
- }
- guard let tokenPayloadDictionary = try? JSONSerialization.jsonObject(
- with: decodedTokenPayloadData,
- options: [.mutableContainers, .allowFragments]
- ) as? [String: Any] else {
- return nil
- }
- // These are dates since 00:00:00 January 1 1970, as described by the Terminology section in
- // the JWT spec. https://tools.ietf.org/html/rfc7519
- let decoder = JSONDecoder()
- decoder.dateDecodingStrategy = .secondsSince1970
- decoder.keyDecodingStrategy = .convertFromSnakeCase
- guard let jwt = try? decoder.decode(JWT.self, from: decodedTokenPayloadData) else {
- return nil
- }
- let tokenResult = AuthTokenResult(token: token,
- expirationDate: jwt.exp,
- authDate: jwt.authTime,
- issuedAtDate: jwt.iat,
- signInProvider: jwt.firebase.signInProvider,
- signInSecondFactor: jwt.firebase.signInSecondFactor,
- claims: tokenPayloadDictionary)
- return tokenResult
- }
- init(token: String,
- expirationDate: Date,
- authDate: Date,
- issuedAtDate: Date,
- signInProvider: String,
- signInSecondFactor: String?,
- claims: [String: Any]) {
- self.token = token
- self.expirationDate = expirationDate
- self.authDate = authDate
- self.issuedAtDate = issuedAtDate
- self.signInProvider = signInProvider
- self.signInSecondFactor = signInSecondFactor
- self.claims = claims
- }
- }
- struct JWT: Decodable {
- struct FirebasePayload: Decodable {
- let signInProvider: String
- let signInSecondFactor: String?
- }
- let exp: Date
- let authTime: Date
- let iat: Date
- let firebase: FirebasePayload
- }
- /*
- @implementation FIRAuthTokenResult
- + (nullable FIRAuthTokenResult *)tokenResultWithToken:(NSString *)token {
- }
- #pragma mark - NSSecureCoding
- + (BOOL)supportsSecureCoding {
- return YES;
- }
- - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
- NSString *token = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kTokenKey];
- return [FIRAuthTokenResult tokenResultWithToken:token];
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:_token forKey:kTokenKey];
- }
- @end
- */
|