|
1 |
| -import 'dart:convert'; |
2 |
| - |
3 | 1 | import 'package:http/http.dart' as http;
|
| 2 | +import 'package:logto_dart_sdk/src/interfaces/logto_user_info_response.dart'; |
4 | 3 |
|
5 |
| -import '/src/exceptions/http_request_exceptions.dart'; |
6 |
| -import '/src/interfaces/oidc_provider_config.dart'; |
| 4 | +import '/src/interfaces/logto_interfaces.dart'; |
7 | 5 | import '/src/utilities/utils.dart';
|
| 6 | +import '/src/utilities/http_utils.dart'; |
| 7 | +import '/src/utilities/constants.dart'; |
| 8 | + |
| 9 | +const String _codeChallengeMethod = 'S256'; |
| 10 | +const String _responseType = 'code'; |
| 11 | +const String _prompt = 'consent'; |
| 12 | +const String _requestContentType = 'application/x-www-form-urlencoded'; |
| 13 | + |
| 14 | +Future<OidcProviderConfig> fetchOidcConfig( |
| 15 | + http.Client httpClient, String endpoint) async { |
| 16 | + final response = await httpClient.get(Uri.parse(endpoint)); |
| 17 | + |
| 18 | + var body = httpResponseHandler(response); |
| 19 | + |
| 20 | + return OidcProviderConfig.fromJson(body); |
| 21 | +} |
8 | 22 |
|
9 |
| -class LogtoCore { |
10 |
| - static const String codeChallengeMethod = 'S256'; |
11 |
| - static const String responseType = 'code'; |
12 |
| - static const String prompt = 'consent'; |
| 23 | +Future<LogtoCodeTokenResponse> fetchTokenByAuthorizationCode( |
| 24 | + {required http.Client httpClient, |
| 25 | + required String tokenEndPoint, |
| 26 | + required String code, |
| 27 | + required String codeVerifier, |
| 28 | + required String clientId, |
| 29 | + required String redirectUri, |
| 30 | + String? resource}) async { |
| 31 | + Map<String, dynamic> payload = { |
| 32 | + 'grant_type': authorizationCodeGrantType, |
| 33 | + 'code': code, |
| 34 | + 'code_verifier': codeVerifier, |
| 35 | + 'client_id': clientId, |
| 36 | + 'redirect_uri': redirectUri, |
| 37 | + }; |
13 | 38 |
|
14 |
| - static Future<OidcProviderConfig> fetchOidcConfig( |
15 |
| - String endpoint, http.Client httpClient) async { |
16 |
| - final response = await httpClient.get(Uri.parse(endpoint)); |
| 39 | + if (resource != null && resource.isNotEmpty) { |
| 40 | + payload.addAll({'resource': resource}); |
| 41 | + } |
| 42 | + |
| 43 | + final response = await httpClient.post(Uri.parse(tokenEndPoint), |
| 44 | + headers: {'Content-Type': _requestContentType}, body: payload); |
| 45 | + |
| 46 | + var body = httpResponseHandler(response); |
17 | 47 |
|
18 |
| - var body = jsonDecode(response.body); |
| 48 | + return LogtoCodeTokenResponse.fromJson(body); |
| 49 | +} |
19 | 50 |
|
20 |
| - if (response.statusCode < 200 || response.statusCode >= 300) { |
21 |
| - throw HttpRequestException(statusCode: response.statusCode, body: body); |
22 |
| - } |
| 51 | +Future<LogtoRefreshTokenResponse> fetchTokenByRefreshToken({ |
| 52 | + required http.Client httpClient, |
| 53 | + required String tokenEndPoint, |
| 54 | + required String clientId, |
| 55 | + required String refreshToken, |
| 56 | + String? resource, |
| 57 | + List<String>? scopes, |
| 58 | +}) async { |
| 59 | + Map<String, dynamic> payload = { |
| 60 | + 'grant_type': refreshTokenGrantType, |
| 61 | + 'client_id': clientId, |
| 62 | + 'refresh_token': refreshToken, |
| 63 | + }; |
23 | 64 |
|
24 |
| - return OidcProviderConfig.fromJson(body); |
| 65 | + if (resource != null && resource.isNotEmpty) { |
| 66 | + payload.addAll({'resource': resource}); |
25 | 67 | }
|
26 | 68 |
|
27 |
| - static Uri generateSignInUri( |
28 |
| - {required String authorizationEndpoint, |
29 |
| - required clientId, |
30 |
| - required Uri redirectUri, |
31 |
| - required String codeChallenge, |
32 |
| - required String state, |
33 |
| - List<String> scopes = const [], |
34 |
| - List<String>? resources, |
35 |
| - String prompt = LogtoCore.prompt}) { |
36 |
| - var signInUri = Uri.parse(authorizationEndpoint); |
37 |
| - |
38 |
| - Map<String, dynamic> queryParameters = { |
39 |
| - 'client_id': clientId, |
40 |
| - 'redirect_uri': redirectUri.toString(), |
41 |
| - 'code_challenge': codeChallenge, |
42 |
| - 'code_challenge_method': LogtoCore.codeChallengeMethod, |
43 |
| - 'state': state, |
44 |
| - 'scope': withReservedScopes(scopes).join(' '), |
45 |
| - 'response_type': LogtoCore.responseType, |
46 |
| - 'prompt': prompt, |
47 |
| - }; |
48 |
| - |
49 |
| - if (resources != null && resources.isNotEmpty) { |
50 |
| - queryParameters.addAll({'resources': resources}); |
51 |
| - } |
52 |
| - |
53 |
| - return addQueryParameters(signInUri, queryParameters); |
| 69 | + if (scopes != null && scopes.isNotEmpty) { |
| 70 | + payload.addAll({'scope': scopes.join(' ')}); |
54 | 71 | }
|
55 | 72 |
|
56 |
| - static Uri generateSignOutUri( |
57 |
| - {required String endSessionEndpoint, |
58 |
| - required String idToken, |
59 |
| - required Uri postLogoutRedirectUri}) { |
60 |
| - var signOutUri = Uri.parse(endSessionEndpoint); |
| 73 | + final response = await httpClient.post(Uri.parse(tokenEndPoint), |
| 74 | + headers: {'Content-Type': _requestContentType}, body: payload); |
| 75 | + |
| 76 | + var body = httpResponseHandler(response); |
| 77 | + |
| 78 | + return LogtoRefreshTokenResponse.fromJson(body); |
| 79 | +} |
| 80 | + |
| 81 | +Future<LogtoUserInfoResponse> fetchUserInfo( |
| 82 | + {required http.Client httpClient, |
| 83 | + required String userInfoEndpoint, |
| 84 | + required String accessToken}) async { |
| 85 | + final response = await httpClient.post(Uri.parse(userInfoEndpoint), |
| 86 | + headers: {'Authorization': 'Bearer $accessToken'}); |
| 87 | + |
| 88 | + var body = httpResponseHandler(response); |
| 89 | + |
| 90 | + return LogtoUserInfoResponse.fromJson(body); |
| 91 | +} |
| 92 | + |
| 93 | +Future<void> revoke({ |
| 94 | + required http.Client httpClient, |
| 95 | + required String revocationEndpoint, |
| 96 | + required String clientId, |
| 97 | + required String token, |
| 98 | +}) => |
| 99 | + httpClient.post(Uri.parse(revocationEndpoint), |
| 100 | + headers: {'Content-Type': _requestContentType}, |
| 101 | + body: {'client_id': clientId, 'token': token}); |
61 | 102 |
|
62 |
| - return addQueryParameters(signOutUri, { |
63 |
| - 'id_token_hint': idToken, |
64 |
| - 'post_logout_redirect_uri': postLogoutRedirectUri.toString() |
65 |
| - }); |
| 103 | +Uri generateSignInUri( |
| 104 | + {required String authorizationEndpoint, |
| 105 | + required clientId, |
| 106 | + required Uri redirectUri, |
| 107 | + required String codeChallenge, |
| 108 | + required String state, |
| 109 | + List<String> scopes = const [], |
| 110 | + List<String>? resources, |
| 111 | + String prompt = _prompt}) { |
| 112 | + var signInUri = Uri.parse(authorizationEndpoint); |
| 113 | + |
| 114 | + Map<String, dynamic> queryParameters = { |
| 115 | + 'client_id': clientId, |
| 116 | + 'redirect_uri': redirectUri.toString(), |
| 117 | + 'code_challenge': codeChallenge, |
| 118 | + 'code_challenge_method': _codeChallengeMethod, |
| 119 | + 'state': state, |
| 120 | + 'scope': withReservedScopes(scopes).join(' '), |
| 121 | + 'response_type': _responseType, |
| 122 | + 'prompt': prompt, |
| 123 | + }; |
| 124 | + |
| 125 | + if (resources != null && resources.isNotEmpty) { |
| 126 | + queryParameters.addAll({'resources': resources}); |
66 | 127 | }
|
| 128 | + |
| 129 | + return addQueryParameters(signInUri, queryParameters); |
| 130 | +} |
| 131 | + |
| 132 | +Uri generateSignOutUri( |
| 133 | + {required String endSessionEndpoint, |
| 134 | + required String idToken, |
| 135 | + required Uri postLogoutRedirectUri}) { |
| 136 | + var signOutUri = Uri.parse(endSessionEndpoint); |
| 137 | + |
| 138 | + return addQueryParameters(signOutUri, { |
| 139 | + 'id_token_hint': idToken, |
| 140 | + 'post_logout_redirect_uri': postLogoutRedirectUri.toString() |
| 141 | + }); |
67 | 142 | }
|
0 commit comments