Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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/Foundation.h>

@class GIDSignInInternalOptions;
@class OIDAuthorizationResponse;

NS_ASSUME_NONNULL_BEGIN

/// The protocol to control the authorization flow.
@protocol GIDAuthorizationFlowProcessor <NSObject>

/// The state of the authorization flow.
@property(nonatomic, readonly, getter=isStarted) BOOL start;

/// Starts the authorization flow.
///
/// This method sends authorization request to AppAuth `OIDAuthorizationService` and gets back the
/// response or an error.
///
/// @param options The `GIDSignInInternalOptions` object to provide serverClientID, hostedDomain,
/// clientID, scopes, loginHint and extraParams.
/// @param emmSupport The EMM support info string.
/// @param completion The block that is called on completion asynchronously.
/// authorizationResponse The response from `OIDAuthorizationService`.
/// error The error from `OIDAuthorizationService`.
- (void)startWithOptions:(GIDSignInInternalOptions *)options
emmSupport:(nullable NSString *)emmSupport
completion:(void (^)(OIDAuthorizationResponse *_Nullable authorizationResponse,
NSError *_Nullable error))completion;

/// Handles the custom URL scheme opened by SFSafariViewController and returns control to the
/// client on iOS 10.
///
/// @param url The redirect URL invoked by the server.
/// @return YES if the passed URL matches the expected redirect URL and was consumed, NO otherwise.
- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)url;

/// Cancels the authorization flow.
- (void)cancelAuthenticationFlow;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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/Foundation.h>

#import "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/API/GIDAuthorizationFlowProcessor.h"

@class OIDServiceConfiguration;

NS_ASSUME_NONNULL_BEGIN

/// Concrete implementation of the protocol `GIDAuthorizationFlowProcessor`.
@interface GIDAuthorizationFlowProcessor : NSObject <GIDAuthorizationFlowProcessor>

@end

NS_ASSUME_NONNULL_END

Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* 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 "GoogleSignIn/Sources/GIDAuthorizationFlowProcessor/Implementations/GIDAuthorizationFlowProcessor.h"

#import "GoogleSignIn/Sources/Public/GoogleSignIn/GIDConfiguration.h"

#import "GoogleSignIn/Sources/GIDEMMSupport.h"
#import "GoogleSignIn/Sources/GIDSignInCallbackSchemes.h"
#import "GoogleSignIn/Sources/GIDSignInInternalOptions.h"
#import "GoogleSignIn/Sources/GIDSignInPreferences.h"

#ifdef SWIFT_PACKAGE
@import AppAuth;
#else
#import <AppAuth/AppAuth.h>
#endif

NS_ASSUME_NONNULL_BEGIN

// Parameters for the auth and token exchange endpoints.
static NSString *const kAudienceParameter = @"audience";

static NSString *const kIncludeGrantedScopesParameter = @"include_granted_scopes";
static NSString *const kLoginHintParameter = @"login_hint";
static NSString *const kHostedDomainParameter = @"hd";

@interface GIDAuthorizationFlowProcessor ()

/// AppAuth external user-agent session state.
@property(nonatomic, nullable)id<OIDExternalUserAgentSession> currentAuthorizationFlow;

/// AppAuth configuration object.
@property(nonatomic)OIDServiceConfiguration *appAuthConfiguration;

@end

@implementation GIDAuthorizationFlowProcessor

# pragma mark - Public API

- (BOOL)isStarted {
return self.currentAuthorizationFlow != nil;
}

- (void)startWithOptions:(GIDSignInInternalOptions *)options
emmSupport:(nullable NSString *)emmSupport
completion:(void (^)(OIDAuthorizationResponse *_Nullable authorizationResponse,
NSError *_Nullable error))completion {
GIDSignInCallbackSchemes *schemes =
[[GIDSignInCallbackSchemes alloc] initWithClientIdentifier:options.configuration.clientID];
NSString *urlString = [NSString stringWithFormat:@"%@:%@",
[schemes clientIdentifierScheme], kBrowserCallbackPath];
NSURL *redirectURL = [NSURL URLWithString:urlString];

NSMutableDictionary<NSString *, NSString *> *additionalParameters = [@{} mutableCopy];
additionalParameters[kIncludeGrantedScopesParameter] = @"true";
if (options.configuration.serverClientID) {
additionalParameters[kAudienceParameter] = options.configuration.serverClientID;
}
if (options.loginHint) {
additionalParameters[kLoginHintParameter] = options.loginHint;
}
if (options.configuration.hostedDomain) {
additionalParameters[kHostedDomainParameter] = options.configuration.hostedDomain;
}

#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
[additionalParameters addEntriesFromDictionary:
[GIDEMMSupport parametersWithParameters:options.extraParams
emmSupport:emmSupport
isPasscodeInfoRequired:NO]];
#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST
[additionalParameters addEntriesFromDictionary:options.extraParams];
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
additionalParameters[kSDKVersionLoggingParameter] = GIDVersion();
additionalParameters[kEnvironmentLoggingParameter] = GIDEnvironment();

NSURL *authorizationEndpointURL = [GIDSignInPreferences authorizationEndpointURL];
NSURL *tokenEndpointURL = [GIDSignInPreferences tokenEndpointURL];
OIDServiceConfiguration *appAuthConfiguration =
[[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authorizationEndpointURL
tokenEndpoint:tokenEndpointURL];
OIDAuthorizationRequest *request =
[[OIDAuthorizationRequest alloc] initWithConfiguration:appAuthConfiguration
clientId:options.configuration.clientID
scopes:options.scopes
redirectURL:redirectURL
responseType:OIDResponseTypeCode
additionalParameters:additionalParameters];

_currentAuthorizationFlow = [OIDAuthorizationService
presentAuthorizationRequest:request
#if TARGET_OS_IOS || TARGET_OS_MACCATALYST
presentingViewController:options.presentingViewController
#elif TARGET_OS_OSX
presentingWindow:options.presentingWindow
#endif // TARGET_OS_OSX
callback:^(OIDAuthorizationResponse *authorizationResponse,
NSError *error) {
completion(authorizationResponse, error);
}];
}

- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)url {
if ([self.currentAuthorizationFlow resumeExternalUserAgentFlowWithURL:url]) {
self.currentAuthorizationFlow = nil;
return YES;
} else {
return NO;
}
}

- (void)cancelAuthenticationFlow {
[self.currentAuthorizationFlow cancel];
self.currentAuthorizationFlow = nil;
}

@end

NS_ASSUME_NONNULL_END
Loading