Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for SFSafariController on iOS #539

Merged
merged 2 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 56 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 @@ -107,7 +108,22 @@ class _MyAppState extends State<MyApp> {
textAlign: TextAlign.center,
),
onPressed: () => _signInWithAutoCodeExchange(
preferEphemeralSession: true),
preferredExternalAgent: ExternalAgentType
.ephemeralAsWebAuthenticationSession),
),
),
if (Platform.isIOS)
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: const Text(
'Sign in with auto code exchange using '
'SFSafariViewController',
textAlign: TextAlign.center,
),
onPressed: () => _signInWithAutoCodeExchange(
preferredExternalAgent:
ExternalAgentType.sfSafariViewController),
),
),
ElevatedButton(
Expand All @@ -123,6 +139,34 @@ class _MyAppState extends State<MyApp> {
: null,
child: const Text('End session'),
),
if (Platform.isIOS || Platform.isMacOS)
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _idToken != null
? () async {
await _endSession(
preferredExternalAgent: ExternalAgentType
.ephemeralAsWebAuthenticationSession);
}
: null,
child:
const Text('End session using ephemeral session'),
)),
if (Platform.isIOS)
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: _idToken != null
? () async {
await _endSession(
preferredExternalAgent: ExternalAgentType
.sfSafariViewController);
}
: null,
child: const Text(
'End session using SFSafariViewController'),
)),
const SizedBox(height: 8),
if (_error != null) Text(_error ?? ''),
const SizedBox(height: 8),
Expand Down Expand Up @@ -156,13 +200,16 @@ class _MyAppState extends State<MyApp> {
);
}

Future<void> _endSession() async {
Future<void> _endSession(
{ExternalAgentType preferredExternalAgent =
ExternalAgentType.asWebAuthenticationSession}) async {
try {
_setBusyState();
await _appAuth.endSession(EndSessionRequest(
idTokenHint: _idToken,
postLogoutRedirectUrl: _postLogoutRedirectUrl,
serviceConfiguration: _serviceConfiguration));
serviceConfiguration: _serviceConfiguration,
preferredExternalAgent: preferredExternalAgent));
_clearSessionInfo();
} catch (e) {
_handleError(e);
Expand Down Expand Up @@ -285,7 +332,8 @@ class _MyAppState extends State<MyApp> {
}

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

Expand All @@ -295,13 +343,10 @@ 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: preferredExternalAgent),
);

/*
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.ephemeralAsWebAuthenticationSession"]) {
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
Loading
Loading