Skip to content

Commit d833f4b

Browse files
authored
feat(dart): add interactionMode props to the signIn method (#33)
1 parent 9e3846e commit d833f4b

File tree

3 files changed

+43
-19
lines changed

3 files changed

+43
-19
lines changed

lib/logto_client.dart

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import '/src/modules/token_storage.dart';
1212
import '/src/utilities/constants.dart';
1313
import '/src/utilities/utils.dart' as utils;
1414
import 'logto_core.dart' as logto_core;
15+
import 'logto_core.dart';
1516

1617
export '/src/interfaces/logto_config.dart';
1718

@@ -69,23 +70,20 @@ class LogtoClient {
6970
return _oidcConfig!;
7071
}
7172

72-
Future<AccessToken?> getAccessToken(
73-
{String? resource, List<String>? scopes}) async {
73+
Future<AccessToken?> getAccessToken({String? resource}) async {
7474
final accessToken = await _tokenStorage.getAccessToken(resource);
7575

7676
if (accessToken != null) {
7777
return accessToken;
7878
}
7979

80-
final token =
81-
await _getAccessTokenByRefreshToken(resource: resource, scopes: scopes);
80+
final token = await _getAccessTokenByRefreshToken(resource);
8281

8382
return token;
8483
}
8584

8685
// RBAC are not supported currently, no resource specific scopes are needed
87-
Future<AccessToken?> _getAccessTokenByRefreshToken(
88-
{String? resource, List<String>? scopes}) async {
86+
Future<AccessToken?> _getAccessTokenByRefreshToken(String? resource) async {
8987
final refreshToken = await _tokenStorage.refreshToken;
9088

9189
if (refreshToken == null) {
@@ -99,19 +97,17 @@ class LogtoClient {
9997
final oidcConfig = await _getOidcConfig(httpClient);
10098

10199
final response = await logto_core.fetchTokenByRefreshToken(
102-
httpClient: httpClient,
103-
tokenEndPoint: oidcConfig.tokenEndpoint,
104-
clientId: config.appId,
105-
refreshToken: refreshToken,
106-
resource: resource,
107-
scopes: scopes);
100+
httpClient: httpClient,
101+
tokenEndPoint: oidcConfig.tokenEndpoint,
102+
clientId: config.appId,
103+
refreshToken: refreshToken,
104+
resource: resource,
105+
);
108106

109-
final responseScopes = response.scope.split(' ');
107+
final scopes = response.scope.split(' ');
110108

111109
await _tokenStorage.setAccessToken(response.accessToken,
112-
expiresIn: response.expiresIn,
113-
resource: resource,
114-
scopes: responseScopes);
110+
expiresIn: response.expiresIn, resource: resource, scopes: scopes);
115111

116112
// renew refresh token
117113
await _tokenStorage.setRefreshToken(response.refreshToken);
@@ -123,7 +119,7 @@ class LogtoClient {
123119
await _tokenStorage.setIdToken(idToken);
124120
}
125121

126-
return await _tokenStorage.getAccessToken(resource, responseScopes);
122+
return await _tokenStorage.getAccessToken(resource, scopes);
127123
} finally {
128124
if (_httpClient == null) httpClient.close();
129125
}
@@ -148,7 +144,8 @@ class LogtoClient {
148144
}
149145
}
150146

151-
Future<void> signIn(String redirectUri) async {
147+
Future<void> signIn(String redirectUri,
148+
[InteractionMode? interactionMode]) async {
152149
if (_loading) {
153150
throw LogtoAuthException(
154151
LogtoAuthExceptions.isLoadingError, 'Already signing in...');
@@ -171,6 +168,7 @@ class LogtoClient {
171168
state: _state,
172169
resources: config.resources,
173170
scopes: config.scopes,
171+
interactionMode: interactionMode,
174172
);
175173
String? callbackUri;
176174

lib/logto_core.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ const String _responseType = 'code';
1212
const String _prompt = 'consent';
1313
const String _requestContentType = 'application/x-www-form-urlencoded';
1414

15+
enum InteractionMode { signIn, signUp }
16+
17+
extension InteractionModeExtension on InteractionMode {
18+
String get value {
19+
switch (this) {
20+
case InteractionMode.signIn:
21+
return 'signIn';
22+
case InteractionMode.signUp:
23+
return 'signUp';
24+
default:
25+
throw Exception("Invalid value");
26+
}
27+
}
28+
}
29+
1530
Future<OidcProviderConfig> fetchOidcConfig(
1631
http.Client httpClient, String endpoint) async {
1732
final response = await httpClient.get(Uri.parse(endpoint));
@@ -109,6 +124,7 @@ Uri generateSignInUri(
109124
required String state,
110125
List<String>? scopes,
111126
List<String>? resources,
127+
InteractionMode? interactionMode,
112128
String prompt = _prompt}) {
113129
var signInUri = Uri.parse(authorizationEndpoint);
114130

@@ -127,6 +143,11 @@ Uri generateSignInUri(
127143
queryParameters.addAll({'resource': resources});
128144
}
129145

146+
if (interactionMode != null) {
147+
// need to align with the backend OIDC params name
148+
queryParameters.addAll({'interaction_mode': interactionMode.value});
149+
}
150+
130151
return addQueryParameters(signInUri, queryParameters);
131152
}
132153

test/logto_core_test.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:convert';
22

33
import 'package:flutter_test/flutter_test.dart';
44
import 'package:http/http.dart' as http;
5+
import 'package:logto_dart_sdk/logto_core.dart';
56
import 'package:nock/nock.dart';
67

78
import 'package:logto_dart_sdk/logto_core.dart' as logto_core;
@@ -24,14 +25,16 @@ void main() {
2425
var redirectUri = 'http://foo.app.io';
2526
const String codeChallenge = 'foo_code_challenge';
2627
const String state = 'foo_state';
28+
const InteractionMode interactionMode = InteractionMode.signUp;
2729

2830
var signInUri = logto_core.generateSignInUri(
2931
authorizationEndpoint: authorizationEndpoint,
3032
clientId: clientId,
3133
redirectUri: redirectUri,
3234
codeChallenge: codeChallenge,
3335
resources: ['http://foo.api'],
34-
state: state);
36+
state: state,
37+
interactionMode: interactionMode);
3538

3639
expect(signInUri.scheme, 'http');
3740
expect(signInUri.host, 'foo.com');
@@ -49,6 +52,8 @@ void main() {
4952
containsPair('scope', reservedScopes.join(' ')));
5053
expect(signInUri.queryParameters, containsPair('response_type', 'code'));
5154
expect(signInUri.queryParameters, containsPair('prompt', 'consent'));
55+
expect(
56+
signInUri.queryParameters, containsPair('interaction_mode', 'signUp'));
5257
});
5358

5459
test('Generate SignOut Uri', () {

0 commit comments

Comments
 (0)