@@ -17,34 +17,12 @@ const String _requestContentType = 'application/x-www-form-urlencoded';
17
17
18
18
/**
19
19
* logto_core.dart
20
- *
21
- * This file is part of the Logto SDK.
20
+ *
21
+ * This file is part of the Logto SDK.
22
22
* It contains the core functionalities of the OIDC authentication flow.
23
23
* Use this module if you want to build your own custom SDK.
24
24
*/
25
25
26
- /**
27
- * By default Logto use sign-in as the landing page for the user.
28
- * Use this enum to specify the interaction mode.
29
- *
30
- * - signIn: The user will be redirected to the sign-in page.
31
- * - signUp: The user will be redirected to the sign-up page.
32
- */
33
- enum InteractionMode { signIn, signUp }
34
-
35
- extension InteractionModeExtension on InteractionMode {
36
- String get value {
37
- switch (this ) {
38
- case InteractionMode .signIn:
39
- return 'signIn' ;
40
- case InteractionMode .signUp:
41
- return 'signUp' ;
42
- default :
43
- throw Exception ("Invalid value" );
44
- }
45
- }
46
- }
47
-
48
26
/**
49
27
* Fetch the OIDC provider configuration.
50
28
*/
@@ -98,7 +76,6 @@ Future<LogtoRefreshTokenResponse> fetchTokenByRefreshToken({
98
76
required String refreshToken,
99
77
String ? resource,
100
78
String ? organizationId,
101
- List <String >? scopes,
102
79
}) async {
103
80
Map <String , dynamic > payload = {
104
81
'grant_type' : refreshTokenGrantType,
@@ -114,10 +91,6 @@ Future<LogtoRefreshTokenResponse> fetchTokenByRefreshToken({
114
91
payload.addAll ({'organization_id' : organizationId});
115
92
}
116
93
117
- if (scopes != null && scopes.isNotEmpty) {
118
- payload.addAll ({'scope' : scopes.join (' ' )});
119
- }
120
-
121
94
final response = await httpClient.post (Uri .parse (tokenEndPoint),
122
95
headers: {'Content-Type' : _requestContentType}, body: payload);
123
96
@@ -158,16 +131,47 @@ Future<void> revoke({
158
131
* Generate the sign-in URI (Authorization URI).
159
132
* This URI will be used to initiate the OIDC authentication flow.
160
133
*/
161
- Uri generateSignInUri (
162
- {required String authorizationEndpoint,
163
- required clientId,
164
- required String redirectUri,
165
- required String codeChallenge,
166
- required String state,
167
- List <String >? scopes,
168
- List <String >? resources,
169
- InteractionMode ? interactionMode,
170
- String prompt = _prompt}) {
134
+ Uri generateSignInUri ({
135
+ required String authorizationEndpoint,
136
+ required clientId,
137
+ required String redirectUri,
138
+ required String codeChallenge,
139
+ required String state,
140
+ String prompt = _prompt,
141
+ List <String >? scopes,
142
+ List <String >? resources,
143
+ String ? loginHint,
144
+ @Deprecated ('Legacy parameter, use firstScreen instead' )
145
+ InteractionMode ? interactionMode,
146
+ /**
147
+ * Direct sign-in is a feature that allows you to skip the sign-in page,
148
+ * and directly sign in the user using a specific social or sso connector.
149
+ *
150
+ * The format should be `social:{connectorTarget}` or `sso:{connectorId}` .
151
+ */
152
+ String ? directSignIn,
153
+ /**
154
+ * The first screen to be shown in the sign-in experience.
155
+ */
156
+ FirstScreen ? firstScreen,
157
+ /**
158
+ * Identifier type of the first screen to be shown in the sign-in experience.
159
+ *
160
+ * This parameter is applicable only when the `firstScreen` is set to
161
+ * either `identifierSignIn` or `identifierRegister
162
+ */
163
+ List <IdentifierType >? identifiers,
164
+ /**
165
+ * Extra parameters to be added to the sign-in URI.
166
+ */
167
+ Map <String , String >? extraParams,
168
+ }) {
169
+ assert (
170
+ isValidDirectSignInFormat (directSignIn),
171
+ 'Invalid format for directSignIn: $directSignIn , '
172
+ 'expected one of `social:{connector}` or `sso:{connector}`' ,
173
+ );
174
+
171
175
var signInUri = Uri .parse (authorizationEndpoint);
172
176
173
177
Map <String , dynamic > queryParameters = {
@@ -194,16 +198,38 @@ Uri generateSignInUri(
194
198
queryParameters.addAll ({'resource' : resources});
195
199
}
196
200
201
+ if (loginHint != null ) {
202
+ queryParameters.addAll ({'login_hint' : loginHint});
203
+ }
204
+
197
205
if (interactionMode != null ) {
198
206
// need to align with the backend OIDC params name
199
207
queryParameters.addAll ({'interaction_mode' : interactionMode.value});
200
208
}
201
209
210
+ if (directSignIn != null ) {
211
+ queryParameters.addAll ({'direct_sign_in' : directSignIn});
212
+ }
213
+
214
+ if (firstScreen != null ) {
215
+ queryParameters.addAll ({'first_screen' : firstScreen.value});
216
+ }
217
+
218
+ if (identifiers != null && identifiers.isNotEmpty) {
219
+ queryParameters.addAll ({
220
+ 'identifier' : identifiers.map ((e) => e.value).join (' ' ),
221
+ });
222
+ }
223
+
224
+ if (extraParams != null ) {
225
+ queryParameters.addAll (extraParams);
226
+ }
227
+
202
228
return addQueryParameters (signInUri, queryParameters);
203
229
}
204
230
205
231
/**
206
- * Generate the sign-out URI (End Session URI).
232
+ * Generate the sign-out URI (End Session URI).
207
233
*/
208
234
Uri generateSignOutUri ({
209
235
required String endSessionEndpoint,
@@ -220,7 +246,7 @@ Uri generateSignOutUri({
220
246
221
247
/**
222
248
* A utility function to verify and parse the code from the authorization callback URI.
223
- *
249
+ *
224
250
* - verify the callback URI
225
251
* - verify the state
226
252
* - error detection
@@ -257,3 +283,13 @@ String verifyAndParseCodeFromCallbackUri(
257
283
258
284
return queryParams['code' ]! ;
259
285
}
286
+
287
+ /**
288
+ * Verify the direct sign-in parameter format.
289
+ */
290
+ bool isValidDirectSignInFormat (String ? directSignIn) {
291
+ if (directSignIn == null ) return true ;
292
+
293
+ RegExp regex = RegExp (r'^(social|sso):[a-zA-Z0-9]+$' );
294
+ return regex.hasMatch (directSignIn);
295
+ }
0 commit comments