Skip to content

Commit c6b9b58

Browse files
authored
Merge branch 'main' into patch-1
2 parents e7ffad0 + 72b9e63 commit c6b9b58

File tree

3 files changed

+79
-16
lines changed

3 files changed

+79
-16
lines changed

GoogleSignIn/Sources/GIDSignIn.m

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -726,14 +726,23 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp
726726
- (OIDAuthorizationRequest *)
727727
authorizationRequestWithOptions:(GIDSignInInternalOptions *)options
728728
additionalParameters:(NSDictionary<NSString *, NSString *> *)additionalParameters {
729-
OIDAuthorizationRequest *request =
730-
[[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration
731-
clientId:options.configuration.clientID
732-
scopes:options.scopes
733-
redirectURL:[self redirectURLWithOptions:options]
734-
responseType:OIDResponseTypeCode
735-
nonce:options.nonce
736-
additionalParameters:additionalParameters];
729+
OIDAuthorizationRequest *request;
730+
if (options.nonce) {
731+
request = [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration
732+
clientId:options.configuration.clientID
733+
scopes:options.scopes
734+
redirectURL:[self redirectURLWithOptions:options]
735+
responseType:OIDResponseTypeCode
736+
nonce:options.nonce
737+
additionalParameters:additionalParameters];
738+
} else {
739+
request = [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration
740+
clientId:options.configuration.clientID
741+
scopes:options.scopes
742+
redirectURL:[self redirectURLWithOptions:options]
743+
responseType:OIDResponseTypeCode
744+
additionalParameters:additionalParameters];
745+
}
737746
return request;
738747
}
739748

@@ -918,10 +927,10 @@ - (void)maybeFetchToken:(GIDAuthFlow *)authFlow {
918927
}
919928

920929
[authFlow wait];
921-
[OIDAuthorizationService
922-
performTokenRequest:tokenRequest
923-
callback:^(OIDTokenResponse *_Nullable tokenResponse,
924-
NSError *_Nullable error) {
930+
[OIDAuthorizationService performTokenRequest:tokenRequest
931+
originalAuthorizationResponse:authFlow.authState.lastAuthorizationResponse
932+
callback:^(OIDTokenResponse *_Nullable tokenResponse,
933+
NSError *_Nullable error) {
925934
[authState updateWithTokenResponse:tokenResponse error:error];
926935
authFlow.error = error;
927936

GoogleSignIn/Tests/Unit/GIDSignInTest.m

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ - (void)setUp {
297297
#elif TARGET_OS_OSX
298298
_presentingWindow = OCMStrictClassMock([NSWindow class]);
299299
#endif // TARGET_OS_IOS || TARGET_OS_MACCATALYST
300-
_authState = OCMStrictClassMock([OIDAuthState class]);
300+
_authState = OCMClassMock([OIDAuthState class]);
301301
OCMStub([_authState alloc]).andReturn(_authState);
302302
OCMStub([_authState initWithAuthorizationResponse:OCMOCK_ANY]).andReturn(_authState);
303303
_tokenResponse = OCMStrictClassMock([OIDTokenResponse class]);
@@ -327,7 +327,8 @@ - (void)setUp {
327327
callback:COPY_TO_ARG_BLOCK(self->_savedAuthorizationCallback)]);
328328
OCMStub([self->_oidAuthorizationService
329329
performTokenRequest:SAVE_TO_ARG_BLOCK(self->_savedTokenRequest)
330-
callback:COPY_TO_ARG_BLOCK(self->_savedTokenCallback)]);
330+
originalAuthorizationResponse:[OCMArg any]
331+
callback:COPY_TO_ARG_BLOCK(self->_savedTokenCallback)]);
331332

332333
// Fakes
333334
_fetcherService = [[GIDFakeFetcherService alloc] init];

Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,28 @@ final class GoogleSignInAuthenticator: ObservableObject {
3535
print("There is no root view controller!")
3636
return
3737
}
38-
39-
GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in
38+
let manualNonce = UUID().uuidString
39+
40+
GIDSignIn.sharedInstance.signIn(
41+
withPresenting: rootViewController,
42+
hint: nil,
43+
additionalScopes: nil,
44+
nonce: manualNonce
45+
) { signInResult, error in
4046
guard let signInResult = signInResult else {
4147
print("Error! \(String(describing: error))")
4248
return
4349
}
50+
51+
// Per OpenID Connect Core section 3.1.3.7, rule #11, compare returned nonce to manual
52+
guard let idToken = signInResult.user.idToken?.tokenString,
53+
let returnedNonce = self.decodeNonce(fromJWT: idToken),
54+
returnedNonce == manualNonce else {
55+
// Assert a failure for convenience so that integration tests with this sample app fail upon
56+
// `nonce` mismatch
57+
assertionFailure("ERROR: Returned nonce doesn't match manual nonce!")
58+
return
59+
}
4460
self.authViewModel.state = .signedIn(signInResult.user)
4561
}
4662

@@ -125,3 +141,40 @@ final class GoogleSignInAuthenticator: ObservableObject {
125141
}
126142

127143
}
144+
145+
// MARK: Parse nonce from JWT ID Token
146+
147+
private extension GoogleSignInAuthenticator {
148+
func decodeNonce(fromJWT jwt: String) -> String? {
149+
let segments = jwt.components(separatedBy: ".")
150+
guard let parts = decodeJWTSegment(segments[1]),
151+
let nonce = parts["nonce"] as? String else {
152+
return nil
153+
}
154+
return nonce
155+
}
156+
157+
func decodeJWTSegment(_ segment: String) -> [String: Any]? {
158+
guard let segmentData = base64UrlDecode(segment),
159+
let segmentJSON = try? JSONSerialization.jsonObject(with: segmentData, options: []),
160+
let payload = segmentJSON as? [String: Any] else {
161+
return nil
162+
}
163+
return payload
164+
}
165+
166+
func base64UrlDecode(_ value: String) -> Data? {
167+
var base64 = value
168+
.replacingOccurrences(of: "-", with: "+")
169+
.replacingOccurrences(of: "_", with: "/")
170+
171+
let length = Double(base64.lengthOfBytes(using: String.Encoding.utf8))
172+
let requiredLength = 4 * ceil(length / 4.0)
173+
let paddingLength = requiredLength - length
174+
if paddingLength > 0 {
175+
let padding = "".padding(toLength: Int(paddingLength), withPad: "=", startingAt: 0)
176+
base64 = base64 + padding
177+
}
178+
return Data(base64Encoded: base64, options: .ignoreUnknownCharacters)
179+
}
180+
}

0 commit comments

Comments
 (0)