@@ -36,12 +36,14 @@ final class GoogleSignInAuthenticator: ObservableObject {
3636 return
3737 }
3838 let manualNonce = UUID ( ) . uuidString
39+ let tokenClaims : Set < GIDTokenClaim > = Set ( [ GIDTokenClaim . authTime ( ) ] )
3940
4041 GIDSignIn . sharedInstance. signIn (
4142 withPresenting: rootViewController,
4243 hint: nil ,
4344 additionalScopes: nil ,
44- nonce: manualNonce
45+ nonce: manualNonce,
46+ tokenClaims: tokenClaims
4547 ) { signInResult, error in
4648 guard let signInResult = signInResult else {
4749 print ( " Error! \( String ( describing: error) ) " )
@@ -57,6 +59,10 @@ final class GoogleSignInAuthenticator: ObservableObject {
5759 assertionFailure ( " ERROR: Returned nonce doesn't match manual nonce! " )
5860 return
5961 }
62+ if let authTimeDate = self . decodeAuthTime ( fromJWT: idToken) {
63+ self . authViewModel. authTime = authTimeDate
64+ UserDefaults . standard. set ( authTimeDate, forKey: " authTime " )
65+ }
6066 self . authViewModel. state = . signedIn( signInResult. user)
6167 }
6268
@@ -66,11 +72,27 @@ final class GoogleSignInAuthenticator: ObservableObject {
6672 return
6773 }
6874
69- GIDSignIn . sharedInstance. signIn ( withPresenting: presentingWindow) { signInResult, error in
75+ let tokenClaims : Set < GIDTokenClaim > = Set ( [ GIDTokenClaim . authTime ( ) ] )
76+
77+ GIDSignIn . sharedInstance. signIn (
78+ withPresenting: presentingWindow,
79+ tokenClaims: tokenClaims
80+ ) { signInResult, error in
7081 guard let signInResult = signInResult else {
7182 print ( " Error! \( String ( describing: error) ) " )
7283 return
7384 }
85+
86+ // If the idToken is nil, we cannot get the authTime, so we treat this
87+ // as a failure for the app's sign-in flow and return.
88+ guard let idToken = signInResult. user. idToken? . tokenString else {
89+ print ( " Error: idToken is missing from signInResult. " )
90+ return
91+ }
92+ if let authTimeDate = self . decodeAuthTime ( fromJWT: idToken) {
93+ self . authViewModel. authTime = authTimeDate
94+ UserDefaults . standard. set ( authTimeDate, forKey: " authTime " )
95+ }
7496 self . authViewModel. state = . signedIn( signInResult. user)
7597 }
7698#endif
@@ -154,6 +176,16 @@ private extension GoogleSignInAuthenticator {
154176 return nonce
155177 }
156178
179+ func decodeAuthTime( fromJWT jwt: String ) -> Date ? {
180+ let segments = jwt. components ( separatedBy: " . " )
181+ guard segments. count > 1 ,
182+ let parts = decodeJWTSegment ( segments [ 1 ] ) ,
183+ let authTimeInterval = parts [ " auth_time " ] as? TimeInterval else {
184+ return nil
185+ }
186+ return Date ( timeIntervalSince1970: authTimeInterval)
187+ }
188+
157189 func decodeJWTSegment( _ segment: String ) -> [ String : Any ] ? {
158190 guard let segmentData = base64UrlDecode ( segment) ,
159191 let segmentJSON = try ? JSONSerialization . jsonObject ( with: segmentData, options: [ ] ) ,
0 commit comments