Skip to content

Commit 461a49e

Browse files
committed
feat: add flexible state parameter handling for authorization and end-session requests
1 parent 4e09321 commit 461a49e

14 files changed

Lines changed: 175 additions & 51 deletions

File tree

flutter_appauth/android/src/main/java/io/crossingthestreams/flutterappauth/FlutterAppauthPlugin.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ private AuthorizationTokenRequestParameters processAuthorizationTokenRequestArgu
221221
(Map<String, String>) arguments.get("additionalParameters");
222222
allowInsecureConnections = (boolean) arguments.get("allowInsecureConnections");
223223
final String responseMode = (String) arguments.get("responseMode");
224+
final RequestState state = arguments.containsKey("state")
225+
? new RequestState((String) arguments.get("state"))
226+
: null;
224227

225228
return new AuthorizationTokenRequestParameters(
226229
clientId,
@@ -233,7 +236,8 @@ private AuthorizationTokenRequestParameters processAuthorizationTokenRequestArgu
233236
loginHint,
234237
nonce,
235238
promptValues,
236-
responseMode);
239+
responseMode,
240+
state);
237241
}
238242

239243
@SuppressWarnings("unchecked")
@@ -286,7 +290,9 @@ private EndSessionRequestParameters processEndSessionRequestArguments(
286290
Map<String, Object> arguments) {
287291
final String idTokenHint = (String) arguments.get("idTokenHint");
288292
final String postLogoutRedirectUrl = (String) arguments.get("postLogoutRedirectUrl");
289-
final String state = (String) arguments.get("state");
293+
final RequestState state = arguments.containsKey("state")
294+
? new RequestState((String) arguments.get("state"))
295+
: null;
290296
final boolean allowInsecureConnections = (boolean) arguments.get("allowInsecureConnections");
291297
final String issuer = (String) arguments.get("issuer");
292298
final String discoveryUrl = (String) arguments.get("discoveryUrl");
@@ -323,7 +329,8 @@ private void handleAuthorizeMethodCall(
323329
tokenRequestParameters.additionalParameters,
324330
exchangeCode,
325331
tokenRequestParameters.promptValues,
326-
tokenRequestParameters.responseMode);
332+
tokenRequestParameters.responseMode,
333+
tokenRequestParameters.state);
327334
} else {
328335
AuthorizationServiceConfiguration.RetrieveConfigurationCallback callback =
329336
new AuthorizationServiceConfiguration.RetrieveConfigurationCallback() {
@@ -342,7 +349,8 @@ public void onFetchConfigurationCompleted(
342349
tokenRequestParameters.additionalParameters,
343350
exchangeCode,
344351
tokenRequestParameters.promptValues,
345-
tokenRequestParameters.responseMode);
352+
tokenRequestParameters.responseMode,
353+
tokenRequestParameters.state);
346354
} else {
347355
finishWithDiscoveryError(ex);
348356
}
@@ -415,7 +423,8 @@ private void performAuthorization(
415423
Map<String, String> additionalParameters,
416424
boolean exchangeCode,
417425
ArrayList<String> promptValues,
418-
String responseMode) {
426+
String responseMode,
427+
@Nullable RequestState state) {
419428
AuthorizationRequest.Builder authRequestBuilder =
420429
new AuthorizationRequest.Builder(
421430
serviceConfiguration, clientId, ResponseTypeValues.CODE, Uri.parse(redirectUrl));
@@ -461,6 +470,10 @@ private void performAuthorization(
461470
authRequestBuilder.setAdditionalParameters(additionalParameters);
462471
}
463472

473+
if (state != null) {
474+
authRequestBuilder.setState(state.value);
475+
}
476+
464477
AuthorizationService authorizationService = getAuthorizationService();
465478

466479
try {
@@ -571,7 +584,7 @@ private void performEndSessionRequest(
571584
}
572585

573586
if (endSessionRequestParameters.state != null) {
574-
endSessionRequestBuilder.setState(endSessionRequestParameters.state);
587+
endSessionRequestBuilder.setState(endSessionRequestParameters.state.value);
575588
}
576589

577590
if (endSessionRequestParameters.additionalParameters != null) {
@@ -827,10 +840,17 @@ private TokenRequestParameters(
827840
}
828841
}
829842

843+
/** Wraps an explicit state value from the method channel.
844+
* null state = key absent (auto-generate); non-null = key was present (null value = suppress, String = custom). */
845+
private static class RequestState {
846+
@Nullable final String value;
847+
RequestState(@Nullable String value) { this.value = value; }
848+
}
849+
830850
private class EndSessionRequestParameters {
831851
final String idTokenHint;
832852
final String postLogoutRedirectUrl;
833-
final String state;
853+
@Nullable final RequestState state;
834854
final String issuer;
835855
final String discoveryUrl;
836856
final boolean allowInsecureConnections;
@@ -840,7 +860,7 @@ private class EndSessionRequestParameters {
840860
private EndSessionRequestParameters(
841861
String idTokenHint,
842862
String postLogoutRedirectUrl,
843-
String state,
863+
@Nullable RequestState state,
844864
String issuer,
845865
String discoveryUrl,
846866
boolean allowInsecureConnections,
@@ -861,6 +881,7 @@ private class AuthorizationTokenRequestParameters extends TokenRequestParameters
861881
final String loginHint;
862882
final ArrayList<String> promptValues;
863883
final String responseMode;
884+
@Nullable final RequestState state;
864885

865886
private AuthorizationTokenRequestParameters(
866887
String clientId,
@@ -873,7 +894,8 @@ private AuthorizationTokenRequestParameters(
873894
String loginHint,
874895
String nonce,
875896
ArrayList<String> promptValues,
876-
String responseMode) {
897+
String responseMode,
898+
@Nullable RequestState state) {
877899
super(
878900
clientId,
879901
issuer,
@@ -890,6 +912,7 @@ private AuthorizationTokenRequestParameters(
890912
this.loginHint = loginHint;
891913
this.promptValues = promptValues;
892914
this.responseMode = responseMode;
915+
this.state = state;
893916
}
894917
}
895918
}

flutter_appauth/ios/flutter_appauth/Sources/flutter_appauth/AppAuthIOSAuthorization.m

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ @implementation AppAuthIOSAuthorization
1212
externalUserAgent:(NSNumber *)externalUserAgent
1313
result:(FlutterResult)result
1414
exchangeCode:(BOOL)exchangeCode
15-
nonce:(NSString *)nonce {
15+
nonce:(NSString *)nonce
16+
state:(id)state {
1617
NSString *codeVerifier = [OIDAuthorizationRequest generateCodeVerifier];
1718
NSString *codeChallenge =
1819
[OIDAuthorizationRequest codeChallengeS256ForVerifier:codeVerifier];
20+
NSString *resolvedState = (state != nil)
21+
? ([state isKindOfClass:[NSString class]] ? state : nil)
22+
: [OIDAuthorizationRequest generateState];
1923

2024
OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc]
2125
initWithConfiguration:serviceConfiguration
@@ -24,7 +28,7 @@ @implementation AppAuthIOSAuthorization
2428
scope:[OIDScopeUtilities scopesWithArray:scopes]
2529
redirectURL:[NSURL URLWithString:redirectUrl]
2630
responseType:OIDResponseTypeCode
27-
state:[OIDAuthorizationRequest generateState]
31+
state:resolvedState
2832
nonce:nonce != nil
2933
? nonce
3034
: [OIDAuthorizationRequest generateState]
@@ -119,19 +123,18 @@ @implementation AppAuthIOSAuthorization
119123
? [NSURL URLWithString:requestParameters.postLogoutRedirectUrl]
120124
: nil;
121125

126+
NSString *resolvedState = (requestParameters.state != nil)
127+
? ([requestParameters.state isKindOfClass:[NSString class]]
128+
? requestParameters.state
129+
: nil)
130+
: [OIDAuthorizationRequest generateState];
122131
OIDEndSessionRequest *endSessionRequest =
123-
requestParameters.state
124-
? [[OIDEndSessionRequest alloc]
125-
initWithConfiguration:serviceConfiguration
126-
idTokenHint:requestParameters.idTokenHint
127-
postLogoutRedirectURL:postLogoutRedirectURL
128-
state:requestParameters.state
129-
additionalParameters:requestParameters.additionalParameters]
130-
: [[OIDEndSessionRequest alloc]
131-
initWithConfiguration:serviceConfiguration
132-
idTokenHint:requestParameters.idTokenHint
133-
postLogoutRedirectURL:postLogoutRedirectURL
134-
additionalParameters:requestParameters.additionalParameters];
132+
[[OIDEndSessionRequest alloc]
133+
initWithConfiguration:serviceConfiguration
134+
idTokenHint:requestParameters.idTokenHint
135+
postLogoutRedirectURL:postLogoutRedirectURL
136+
state:resolvedState
137+
additionalParameters:requestParameters.additionalParameters];
135138

136139
UIViewController *rootViewController = [self rootViewController];
137140
id<OIDExternalUserAgent> externalUserAgent =

flutter_appauth/ios/flutter_appauth/Sources/flutter_appauth/FlutterAppAuth.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static NSString *const END_SESSION_ERROR_MESSAGE_FORMAT =
5050
@interface EndSessionRequestParameters : NSObject
5151
@property(nonatomic, strong) NSString *idTokenHint;
5252
@property(nonatomic, strong) NSString *postLogoutRedirectUrl;
53-
@property(nonatomic, strong) NSString *state;
53+
@property(nonatomic, strong) id state;
5454
@property(nonatomic, strong) NSString *issuer;
5555
@property(nonatomic, strong) NSString *discoveryUrl;
5656
@property(nonatomic, strong) NSDictionary *serviceConfigurationParameters;
@@ -76,7 +76,8 @@ typedef NS_ENUM(NSInteger, ExternalUserAgent) {
7676
externalUserAgent:(NSNumber *)externalUserAgent
7777
result:(FlutterResult)result
7878
exchangeCode:(BOOL)exchangeCode
79-
nonce:(NSString *)nonce;
79+
nonce:(NSString *)nonce
80+
state:(id)state;
8081

8182
- (id<OIDExternalUserAgentSession>)
8283
performEndSessionRequest:(OIDServiceConfiguration *)serviceConfiguration

flutter_appauth/ios/flutter_appauth/Sources/flutter_appauth/FlutterAppauthPlugin.m

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ @interface AuthorizationTokenRequestParameters : TokenRequestParameters
8080
@property(nonatomic, strong) NSString *loginHint;
8181
@property(nonatomic, strong) NSArray *promptValues;
8282
@property(nonatomic, strong) NSString *responseMode;
83+
@property(nonatomic, strong) id state; // nil = absent (auto-generate), NSNull = suppress, NSString = custom
8384
@end
8485

8586
@implementation AuthorizationTokenRequestParameters
@@ -91,6 +92,7 @@ - (id)initWithArguments:(NSDictionary *)arguments {
9192
withKey:@"promptValues"];
9293
_responseMode = [ArgumentProcessor processArgumentValue:arguments
9394
withKey:@"responseMode"];
95+
_state = [arguments objectForKey:@"state"];
9496
return self;
9597
}
9698
@end
@@ -102,7 +104,7 @@ - (id)initWithArguments:(NSDictionary *)arguments {
102104
_postLogoutRedirectUrl =
103105
[ArgumentProcessor processArgumentValue:arguments
104106
withKey:@"postLogoutRedirectUrl"];
105-
_state = [ArgumentProcessor processArgumentValue:arguments withKey:@"state"];
107+
_state = [arguments objectForKey:@"state"];
106108
_issuer = [ArgumentProcessor processArgumentValue:arguments
107109
withKey:@"issuer"];
108110
_discoveryUrl = [ArgumentProcessor processArgumentValue:arguments
@@ -211,7 +213,8 @@ - (void)handleAuthorizeMethodCall:(NSDictionary *)arguments
211213
externalUserAgent:requestParameters.externalUserAgent
212214
result:result
213215
exchangeCode:exchangeCode
214-
nonce:requestParameters.nonce];
216+
nonce:requestParameters.nonce
217+
state:requestParameters.state];
215218
} else if (requestParameters.discoveryUrl) {
216219
NSURL *discoveryUrl = [NSURL URLWithString:requestParameters.discoveryUrl];
217220
[OIDAuthorizationService
@@ -253,7 +256,10 @@ - (void)handleAuthorizeMethodCall:(NSDictionary *)arguments
253256
exchangeCode:exchangeCode
254257
nonce:
255258
requestParameters
256-
.nonce];
259+
.nonce
260+
state:
261+
requestParameters
262+
.state];
257263
}];
258264
} else {
259265
NSURL *issuerUrl = [NSURL URLWithString:requestParameters.issuer];
@@ -293,7 +299,10 @@ - (void)handleAuthorizeMethodCall:(NSDictionary *)arguments
293299
exchangeCode:exchangeCode
294300
nonce:
295301
requestParameters
296-
.nonce];
302+
.nonce
303+
state:
304+
requestParameters
305+
.state];
297306
}];
298307
}
299308
}

flutter_appauth/macos/flutter_appauth/Sources/flutter_appauth/AppAuthMacOSAuthorization.m

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ @implementation AppAuthMacOSAuthorization
1212
externalUserAgent:(NSNumber *)externalUserAgent
1313
result:(FlutterResult)result
1414
exchangeCode:(BOOL)exchangeCode
15-
nonce:(NSString *)nonce {
15+
nonce:(NSString *)nonce
16+
state:(id)state {
1617
NSString *codeVerifier = [OIDAuthorizationRequest generateCodeVerifier];
1718
NSString *codeChallenge =
1819
[OIDAuthorizationRequest codeChallengeS256ForVerifier:codeVerifier];
20+
NSString *resolvedState = (state != nil)
21+
? ([state isKindOfClass:[NSString class]] ? state : nil)
22+
: [OIDAuthorizationRequest generateState];
1923

2024
OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc]
2125
initWithConfiguration:serviceConfiguration
@@ -24,7 +28,7 @@ @implementation AppAuthMacOSAuthorization
2428
scope:[OIDScopeUtilities scopesWithArray:scopes]
2529
redirectURL:[NSURL URLWithString:redirectUrl]
2630
responseType:OIDResponseTypeCode
27-
state:[OIDAuthorizationRequest generateState]
31+
state:resolvedState
2832
nonce:nonce != nil
2933
? nonce
3034
: [OIDAuthorizationRequest generateState]
@@ -119,19 +123,18 @@ @implementation AppAuthMacOSAuthorization
119123
? [NSURL URLWithString:requestParameters.postLogoutRedirectUrl]
120124
: nil;
121125

126+
NSString *resolvedState = (requestParameters.state != nil)
127+
? ([requestParameters.state isKindOfClass:[NSString class]]
128+
? requestParameters.state
129+
: nil)
130+
: [OIDAuthorizationRequest generateState];
122131
OIDEndSessionRequest *endSessionRequest =
123-
requestParameters.state
124-
? [[OIDEndSessionRequest alloc]
125-
initWithConfiguration:serviceConfiguration
126-
idTokenHint:requestParameters.idTokenHint
127-
postLogoutRedirectURL:postLogoutRedirectURL
128-
state:requestParameters.state
129-
additionalParameters:requestParameters.additionalParameters]
130-
: [[OIDEndSessionRequest alloc]
131-
initWithConfiguration:serviceConfiguration
132-
idTokenHint:requestParameters.idTokenHint
133-
postLogoutRedirectURL:postLogoutRedirectURL
134-
additionalParameters:requestParameters.additionalParameters];
132+
[[OIDEndSessionRequest alloc]
133+
initWithConfiguration:serviceConfiguration
134+
idTokenHint:requestParameters.idTokenHint
135+
postLogoutRedirectURL:postLogoutRedirectURL
136+
state:resolvedState
137+
additionalParameters:requestParameters.additionalParameters];
135138

136139
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
137140
id<OIDExternalUserAgent> externalUserAgent =

flutter_appauth/macos/flutter_appauth/Sources/flutter_appauth/FlutterAppauthPlugin.m

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ @interface AuthorizationTokenRequestParameters : TokenRequestParameters
8080
@property(nonatomic, strong) NSString *loginHint;
8181
@property(nonatomic, strong) NSArray *promptValues;
8282
@property(nonatomic, strong) NSString *responseMode;
83+
/// Raw value from the method channel: nil = absent (auto-generate), NSNull = suppress, NSString = custom.
84+
@property(nonatomic, strong) id state;
8385
@end
8486

8587
@implementation AuthorizationTokenRequestParameters
@@ -91,6 +93,7 @@ - (id)initWithArguments:(NSDictionary *)arguments {
9193
withKey:@"promptValues"];
9294
_responseMode = [ArgumentProcessor processArgumentValue:arguments
9395
withKey:@"responseMode"];
96+
_state = [arguments objectForKey:@"state"];
9497
return self;
9598
}
9699
@end
@@ -102,7 +105,7 @@ - (id)initWithArguments:(NSDictionary *)arguments {
102105
_postLogoutRedirectUrl =
103106
[ArgumentProcessor processArgumentValue:arguments
104107
withKey:@"postLogoutRedirectUrl"];
105-
_state = [ArgumentProcessor processArgumentValue:arguments withKey:@"state"];
108+
_state = [arguments objectForKey:@"state"];
106109
_issuer = [ArgumentProcessor processArgumentValue:arguments
107110
withKey:@"issuer"];
108111
_discoveryUrl = [ArgumentProcessor processArgumentValue:arguments
@@ -210,7 +213,8 @@ - (void)handleAuthorizeMethodCall:(NSDictionary *)arguments
210213
externalUserAgent:requestParameters.externalUserAgent
211214
result:result
212215
exchangeCode:exchangeCode
213-
nonce:requestParameters.nonce];
216+
nonce:requestParameters.nonce
217+
state:requestParameters.state];
214218
} else if (requestParameters.discoveryUrl) {
215219
NSURL *discoveryUrl = [NSURL URLWithString:requestParameters.discoveryUrl];
216220
[OIDAuthorizationService
@@ -252,7 +256,10 @@ - (void)handleAuthorizeMethodCall:(NSDictionary *)arguments
252256
exchangeCode:exchangeCode
253257
nonce:
254258
requestParameters
255-
.nonce];
259+
.nonce
260+
state:
261+
requestParameters
262+
.state];
256263
}];
257264
} else {
258265
NSURL *issuerUrl = [NSURL URLWithString:requestParameters.issuer];
@@ -292,7 +299,10 @@ - (void)handleAuthorizeMethodCall:(NSDictionary *)arguments
292299
exchangeCode:exchangeCode
293300
nonce:
294301
requestParameters
295-
.nonce];
302+
.nonce
303+
state:
304+
requestParameters
305+
.state];
296306
}];
297307
}
298308
}

flutter_appauth_platform_interface/lib/flutter_appauth_platform_interface.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export 'src/authorization_token_request.dart';
55
export 'src/authorization_token_response.dart';
66
export 'src/end_session_request.dart';
77
export 'src/end_session_response.dart';
8+
export 'src/request_state.dart';
89
export 'src/errors.dart';
910
export 'src/external_user_agent.dart';
1011
export 'src/flutter_appauth_platform.dart';

0 commit comments

Comments
 (0)