Skip to content

Commit

Permalink
Fix passing nil for nonce and add example
Browse files Browse the repository at this point in the history
  • Loading branch information
mdmathias committed Sep 13, 2024
1 parent b34f5a9 commit 20da986
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 13 deletions.
32 changes: 21 additions & 11 deletions GoogleSignIn/Sources/GIDSignIn.m
Original file line number Diff line number Diff line change
Expand Up @@ -726,14 +726,23 @@ - (void)authorizationRequestWithOptions:(GIDSignInInternalOptions *)options comp
- (OIDAuthorizationRequest *)
authorizationRequestWithOptions:(GIDSignInInternalOptions *)options
additionalParameters:(NSDictionary<NSString *, NSString *> *)additionalParameters {
OIDAuthorizationRequest *request =
[[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration
clientId:options.configuration.clientID
scopes:options.scopes
redirectURL:[self redirectURLWithOptions:options]
responseType:OIDResponseTypeCode
nonce:options.nonce
additionalParameters:additionalParameters];
OIDAuthorizationRequest *request;
if (options.nonce) {
request = [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration
clientId:options.configuration.clientID
scopes:options.scopes
redirectURL:[self redirectURLWithOptions:options]
responseType:OIDResponseTypeCode
nonce:options.nonce
additionalParameters:additionalParameters];
} else {
request = [[OIDAuthorizationRequest alloc] initWithConfiguration:_appAuthConfiguration
clientId:options.configuration.clientID
scopes:options.scopes
redirectURL:[self redirectURLWithOptions:options]
responseType:OIDResponseTypeCode
additionalParameters:additionalParameters];
}
return request;
}

Expand Down Expand Up @@ -918,9 +927,10 @@ - (void)maybeFetchToken:(GIDAuthFlow *)authFlow {

[authFlow wait];
[OIDAuthorizationService
performTokenRequest:tokenRequest
callback:^(OIDTokenResponse *_Nullable tokenResponse,
NSError *_Nullable error) {
performTokenRequest:tokenRequest
originalAuthorizationResponse:authFlow.authState.lastAuthorizationResponse
callback:^(OIDTokenResponse *_Nullable tokenResponse,
NSError *_Nullable error) {
[authState updateWithTokenResponse:tokenResponse error:error];
authFlow.error = error;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,26 @@ final class GoogleSignInAuthenticator: ObservableObject {
print("There is no root view controller!")
return
}

GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController) { signInResult, error in
let manualNonce = UUID().uuidString

GIDSignIn.sharedInstance.signIn(
withPresenting: rootViewController,
hint: nil,
additionalScopes: nil,
nonce: manualNonce
) { signInResult, error in
guard let signInResult = signInResult else {
print("Error! \(String(describing: error))")
return
}

// Per OpenID Connect Core section 3.1.3.7, rule #11, compare returned nonce to manual
guard let idToken = signInResult.user.idToken?.tokenString,
let returnedNonce = self.decodeNonce(fromJWT: idToken),
returnedNonce == manualNonce else {
print("ERROR: Returned nonce doesn't match manual nonce!")
return
}
self.authViewModel.state = .signedIn(signInResult.user)
}

Expand Down Expand Up @@ -125,3 +139,40 @@ final class GoogleSignInAuthenticator: ObservableObject {
}

}

// MARK: Parse nonce from JWT ID Token

private extension GoogleSignInAuthenticator {
func decodeNonce(fromJWT jwt: String) -> String? {
let segments = jwt.components(separatedBy: ".")
guard let parts = decodeJWTSegment(segments[1]),
let nonce = parts["nonce"] as? String else {
return nil
}
return nonce
}

func decodeJWTSegment(_ segment: String) -> [String: Any]? {
guard let segmentData = base64UrlDecode(segment),
let segmentJSON = try? JSONSerialization.jsonObject(with: segmentData, options: []),
let payload = segmentJSON as? [String: Any] else {
return nil
}
return payload
}

func base64UrlDecode(_ value: String) -> Data? {
var base64 = value
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")

let length = Double(base64.lengthOfBytes(using: String.Encoding.utf8))
let requiredLength = 4 * ceil(length / 4.0)
let paddingLength = requiredLength - length
if paddingLength > 0 {
let padding = "".padding(toLength: Int(paddingLength), withPad: "=", startingAt: 0)
base64 = base64 + padding
}
return Data(base64Encoded: base64, options: .ignoreUnknownCharacters)
}
}

0 comments on commit 20da986

Please sign in to comment.