Skip to content

Commit

Permalink
appauth: support SFSafariController
Browse files Browse the repository at this point in the history
  • Loading branch information
john-slow committed Sep 24, 2024
1 parent 34d93ac commit f09776c
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 34 deletions.
19 changes: 8 additions & 11 deletions flutter_appauth/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:io' show Platform;
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_appauth/flutter_appauth.dart';
Expand Down Expand Up @@ -106,8 +107,7 @@ class _MyAppState extends State<MyApp> {
'session',
textAlign: TextAlign.center,
),
onPressed: () => _signInWithAutoCodeExchange(
preferEphemeralSession: true),
onPressed: () => _signInWithAutoCodeExchange(),
),
),
ElevatedButton(
Expand Down Expand Up @@ -284,8 +284,7 @@ class _MyAppState extends State<MyApp> {
}
}

Future<void> _signInWithAutoCodeExchange(
{bool preferEphemeralSession = false}) async {
Future<void> _signInWithAutoCodeExchange() async {
try {
_setBusyState();

Expand All @@ -295,13 +294,11 @@ class _MyAppState extends State<MyApp> {
*/
final AuthorizationTokenResponse result =
await _appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
_clientId,
_redirectUrl,
serviceConfiguration: _serviceConfiguration,
scopes: _scopes,
preferEphemeralSession: preferEphemeralSession,
),
AuthorizationTokenRequest(_clientId, _redirectUrl,
serviceConfiguration: _serviceConfiguration,
scopes: _scopes,
preferredExternalAgent:
ExternalAgentType.asWebAuthenticationSession),
);

/*
Expand Down
1 change: 1 addition & 0 deletions flutter_appauth/ios/Classes/AppAuthIOSAuthorization.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import <AppAuth/AppAuth.h>
#import <Flutter/Flutter.h>
#import "OIDExternalUserAgentIOSNoSSO.h"
#import "OIDExternalUserAgentIOSSafariViewController.h"
#import "FlutterAppAuth.h"

NS_ASSUME_NONNULL_BEGIN
Expand Down
20 changes: 12 additions & 8 deletions flutter_appauth/ios/Classes/AppAuthIOSAuthorization.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

@implementation AppAuthIOSAuthorization

- (id<OIDExternalUserAgentSession>) performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferEphemeralSession:(BOOL)preferEphemeralSession result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode nonce:(NSString*)nonce{
- (id<OIDExternalUserAgentSession>) performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferredExternalAgent:(NSString*)preferredExternalAgent result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode nonce:(NSString*)nonce{
NSString *codeVerifier = [OIDAuthorizationRequest generateCodeVerifier];
NSString *codeChallenge = [OIDAuthorizationRequest codeChallengeS256ForVerifier:codeVerifier];

Expand All @@ -21,7 +21,7 @@ @implementation AppAuthIOSAuthorization
additionalParameters:additionalParameters];
UIViewController *rootViewController = [self rootViewController];
if(exchangeCode) {
id<OIDExternalUserAgent> externalUserAgent = [self userAgentWithViewController:rootViewController useEphemeralSession:preferEphemeralSession];
id<OIDExternalUserAgent> externalUserAgent = [self userAgentWithViewController:rootViewController preferredExternalAgent:preferredExternalAgent];
return [OIDAuthState authStateByPresentingAuthorizationRequest:request externalUserAgent:externalUserAgent callback:^(OIDAuthState *_Nullable authState,
NSError *_Nullable error) {
if(authState) {
Expand All @@ -32,7 +32,7 @@ @implementation AppAuthIOSAuthorization
}
}];
} else {
id<OIDExternalUserAgent> externalUserAgent = [self userAgentWithViewController:rootViewController useEphemeralSession:preferEphemeralSession];
id<OIDExternalUserAgent> externalUserAgent = [self userAgentWithViewController:rootViewController preferredExternalAgent:preferredExternalAgent];
return [OIDAuthorizationService presentAuthorizationRequest:request externalUserAgent:externalUserAgent callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse, NSError *_Nullable error) {
if(authorizationResponse) {
NSMutableDictionary *processedResponse = [[NSMutableDictionary alloc] init];
Expand All @@ -56,7 +56,7 @@ @implementation AppAuthIOSAuthorization
additionalParameters:requestParameters.additionalParameters];

UIViewController *rootViewController = [self rootViewController];
id<OIDExternalUserAgent> externalUserAgent = [self userAgentWithViewController:rootViewController useEphemeralSession:requestParameters.preferEphemeralSession];
id<OIDExternalUserAgent> externalUserAgent = [self userAgentWithViewController:rootViewController preferredExternalAgent:requestParameters.preferredExternalAgent];


return [OIDAuthorizationService presentEndSessionRequest:endSessionRequest externalUserAgent:externalUserAgent callback:^(OIDEndSessionResponse * _Nullable endSessionResponse, NSError * _Nullable error) {
Expand All @@ -71,13 +71,17 @@ @implementation AppAuthIOSAuthorization
}];
}

- (id<OIDExternalUserAgent>)userAgentWithViewController:(UIViewController *)rootViewController useEphemeralSession:(BOOL)useEphemeralSession {
if (useEphemeralSession) {
- (id<OIDExternalUserAgent>)userAgentWithViewController:(UIViewController *)rootViewController preferredExternalAgent:(NSString*)preferredExternalAgent {
if ([preferredExternalAgent isEqual:@"ExternalAgentType.EphemeralSession"]) {
return [[OIDExternalUserAgentIOSNoSSO alloc]
initWithPresentingViewController:rootViewController];
} else if ([preferredExternalAgent isEqual:@"ExternalAgentType.SFSafariViewController"]) {
return [[OIDExternalUserAgentIOSSafariViewController alloc]
initWithPresentingViewController:rootViewController];
} else {
return [[OIDExternalUserAgentIOS alloc]
initWithPresentingViewController:rootViewController];
}
return [[OIDExternalUserAgentIOS alloc]
initWithPresentingViewController:rootViewController];
}

- (UIViewController *)rootViewController {
Expand Down
4 changes: 2 additions & 2 deletions flutter_appauth/ios/Classes/FlutterAppAuth.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ static NSString *const END_SESSION_ERROR_MESSAGE_FORMAT = @"Failed to end sessio
@property(nonatomic, strong) NSString *discoveryUrl;
@property(nonatomic, strong) NSDictionary *serviceConfigurationParameters;
@property(nonatomic, strong) NSDictionary *additionalParameters;
@property(nonatomic, readwrite) BOOL preferEphemeralSession;
@property(nonatomic, strong) NSString *preferredExternalAgent;
@end

@interface AppAuthAuthorization : NSObject

- (id<OIDExternalUserAgentSession>)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferEphemeralSession:(BOOL)preferEphemeralSession result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode nonce:(NSString*)nonce;
- (id<OIDExternalUserAgentSession>)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferredExternalAgent:(NSString*)preferredExternalAgent result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode nonce:(NSString*)nonce;

- (id<OIDExternalUserAgentSession>)performEndSessionRequest:(OIDServiceConfiguration *)serviceConfiguration requestParameters:(EndSessionRequestParameters *)requestParameters result:(FlutterResult)result;

Expand Down
2 changes: 1 addition & 1 deletion flutter_appauth/ios/Classes/FlutterAppAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ + (NSString *) formatMessageWithError:(NSString *)messageFormat error:(NSError *

@implementation AppAuthAuthorization

- (id<OIDExternalUserAgentSession>)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferEphemeralSession:(BOOL)preferEphemeralSession result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode nonce:(NSString*)nonce {
- (id<OIDExternalUserAgentSession>)performAuthorization:(OIDServiceConfiguration *)serviceConfiguration clientId:(NSString*)clientId clientSecret:(NSString*)clientSecret scopes:(NSArray *)scopes redirectUrl:(NSString*)redirectUrl additionalParameters:(NSDictionary *)additionalParameters preferredExternalAgent:(NSString*)preferredExternalAgent result:(FlutterResult)result exchangeCode:(BOOL)exchangeCode nonce:(NSString*)nonce {
return nil;
}

Expand Down
12 changes: 6 additions & 6 deletions flutter_appauth/ios/Classes/FlutterAppauthPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ @interface TokenRequestParameters : NSObject
@property(nonatomic, strong) NSArray *scopes;
@property(nonatomic, strong) NSDictionary *serviceConfigurationParameters;
@property(nonatomic, strong) NSDictionary *additionalParameters;
@property(nonatomic, readwrite) BOOL preferEphemeralSession;
@property(nonatomic, strong) NSString *preferredExternalAgent;

@end

Expand All @@ -47,7 +47,7 @@ - (void)processArguments:(NSDictionary *)arguments {
_scopes = [ArgumentProcessor processArgumentValue:arguments withKey:@"scopes"];
_serviceConfigurationParameters = [ArgumentProcessor processArgumentValue:arguments withKey:@"serviceConfiguration"];
_additionalParameters = [ArgumentProcessor processArgumentValue:arguments withKey:@"additionalParameters"];
_preferEphemeralSession = [[ArgumentProcessor processArgumentValue:arguments withKey:@"preferEphemeralSession"] isEqual:@YES];
_preferredExternalAgent = [ArgumentProcessor processArgumentValue:arguments withKey:@"preferredExternalAgent"];
}

- (id)initWithArguments:(NSDictionary *)arguments {
Expand Down Expand Up @@ -82,7 +82,7 @@ - (id)initWithArguments:(NSDictionary *)arguments {
_discoveryUrl = [ArgumentProcessor processArgumentValue:arguments withKey:@"discoveryUrl"];
_serviceConfigurationParameters = [ArgumentProcessor processArgumentValue:arguments withKey:@"serviceConfiguration"];
_additionalParameters = [ArgumentProcessor processArgumentValue:arguments withKey:@"additionalParameters"];
_preferEphemeralSession = [[ArgumentProcessor processArgumentValue:arguments withKey:@"preferEphemeralSession"] isEqual:@YES];
_preferredExternalAgent = [ArgumentProcessor processArgumentValue:arguments withKey:@"preferredExternalAgent"];
return self;
}
@end
Expand Down Expand Up @@ -149,7 +149,7 @@ -(void)handleAuthorizeMethodCall:(NSDictionary*)arguments result:(FlutterResult)

if(requestParameters.serviceConfigurationParameters != nil) {
OIDServiceConfiguration *serviceConfiguration = [self processServiceConfigurationParameters:requestParameters.serviceConfigurationParameters];
_currentAuthorizationFlow = [authorization performAuthorization:serviceConfiguration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferEphemeralSession:requestParameters.preferEphemeralSession result:result exchangeCode:exchangeCode nonce:requestParameters.nonce];
_currentAuthorizationFlow = [authorization performAuthorization:serviceConfiguration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferredExternalAgent:requestParameters.preferredExternalAgent result:result exchangeCode:exchangeCode nonce:requestParameters.nonce];
} else if (requestParameters.discoveryUrl) {
NSURL *discoveryUrl = [NSURL URLWithString:requestParameters.discoveryUrl];
[OIDAuthorizationService discoverServiceConfigurationForDiscoveryURL:discoveryUrl
Expand All @@ -161,7 +161,7 @@ -(void)handleAuthorizeMethodCall:(NSDictionary*)arguments result:(FlutterResult)
return;
}

self->_currentAuthorizationFlow = [authorization performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferEphemeralSession:requestParameters.preferEphemeralSession result:result exchangeCode:exchangeCode nonce:requestParameters.nonce];
self->_currentAuthorizationFlow = [authorization performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferredExternalAgent:requestParameters.preferredExternalAgent result:result exchangeCode:exchangeCode nonce:requestParameters.nonce];
}];
} else {
NSURL *issuerUrl = [NSURL URLWithString:requestParameters.issuer];
Expand All @@ -174,7 +174,7 @@ -(void)handleAuthorizeMethodCall:(NSDictionary*)arguments result:(FlutterResult)
return;
}

self->_currentAuthorizationFlow = [authorization performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferEphemeralSession:requestParameters.preferEphemeralSession result:result exchangeCode:exchangeCode nonce:requestParameters.nonce];
self->_currentAuthorizationFlow = [authorization performAuthorization:configuration clientId:requestParameters.clientId clientSecret:requestParameters.clientSecret scopes:requestParameters.scopes redirectUrl:requestParameters.redirectUrl additionalParameters:requestParameters.additionalParameters preferredExternalAgent:requestParameters.preferredExternalAgent result:result exchangeCode:exchangeCode nonce:requestParameters.nonce];
}];
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*! @file OIDExternalUserAgentIOSSafariViewController.h
@brief AppAuth iOS SDK
@copyright
Copyright 2018 Google Inc. All Rights Reserved.
@copydetails
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 <UIKit/UIKit.h>

#import "OIDExternalUserAgentIOSSafariViewController.h"
#import "OIDExternalUserAgent.h"
#import "OIDExternalUserAgentIOS.h"

NS_ASSUME_NONNULL_BEGIN

/*! @brief Allows library consumers to bootstrap an @c SFSafariViewController as they see fit.
@remarks Useful for customizing tint colors and presentation styles.
*/
@protocol OIDSafariViewControllerFactory

/*! @brief Creates and returns a new @c SFSafariViewController.
@param URL The URL which the @c SFSafariViewController should load initially.
*/
- (SFSafariViewController *)safariViewControllerWithURL:(NSURL *)URL;

@end

/*! @brief A special-case iOS external user-agent that always uses
\SFSafariViewController (on iOS 9+). Most applications should use
the more generic @c OIDExternalUserAgentIOS to get the default
AppAuth user-agent handling with the benefits of Single Sign-on (SSO)
for all supported versions of iOS.
*/
@interface OIDExternalUserAgentIOSSafariViewController : NSObject<OIDExternalUserAgent>

/*! @brief Allows library consumers to change the @c OIDSafariViewControllerFactory used to create
new instances of @c SFSafariViewController.
@remarks Useful for customizing tint colors and presentation styles.
@param factory The @c OIDSafariViewControllerFactory to use for creating new instances of
@c SFSafariViewController.
*/
+ (void)setSafariViewControllerFactory:(id<OIDSafariViewControllerFactory>)factory;

/*! @internal
@brief Unavailable. Please use @c initWithPresentingViewController:
*/
- (nonnull instancetype)init NS_UNAVAILABLE;

/*! @brief The designated initializer.
@param presentingViewController The view controller from which to present the
\SFSafariViewController.
*/
- (nullable instancetype)initWithPresentingViewController:
(UIViewController *)presentingViewController
NS_DESIGNATED_INITIALIZER;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit f09776c

Please sign in to comment.