├── test └── auth0_test.dart ├── lib ├── domain │ ├── telemetry.dart │ └── auth0_user.dart ├── errors │ ├── auth0_unauthorized_exception.dart │ └── auth_exception.dart ├── auth0.dart └── data │ ├── network │ ├── exception_handler.dart │ └── dio_wrapper.dart │ └── auth0_client.dart ├── pubspec.yaml ├── .gitignore ├── LICENSE ├── CHANGELOG.md ├── README.md └── pubspec.lock /test/auth0_test.dart: -------------------------------------------------------------------------------- 1 | void main() {} 2 | -------------------------------------------------------------------------------- /lib/domain/telemetry.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | const telemetry = {'name': 'auth0', 'version': '1.0.0'}; 4 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: auth0 2 | description: Dart package for authentication using Auth0 API. Contains basic set of methods like passwordRealm, getUser, logout etc. 3 | version: 2.2.1 4 | homepage: https://github.com/mishatron/flutter_auth0.git 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dependencies: 10 | dio: ^5.1.2 11 | pretty_dio_logger: ^1.3.1 12 | -------------------------------------------------------------------------------- /lib/errors/auth0_unauthorized_exception.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | /// Class that presents exception unauthorized exception from auth0 4 | class Auth0UnauthorizedException implements Exception { 5 | final String message; 6 | 7 | Auth0UnauthorizedException({required this.message}); 8 | 9 | @override 10 | String toString() { 11 | return "Auth0UnauthorizedException($message)"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/errors/auth_exception.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | /// Class that presents general exception from auth0 4 | class AuthException implements Exception { 5 | final String name; 6 | final String description; 7 | 8 | AuthException( 9 | {this.name = 'a0.response.invalid', this.description = 'unknown error'}); 10 | 11 | @override 12 | String toString() { 13 | return "$name $description"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/auth0.dart: -------------------------------------------------------------------------------- 1 | library auth0; 2 | 3 | import 'dart:convert'; 4 | import 'dart:io'; 5 | 6 | import 'package:dio/dio.dart'; 7 | import 'package:pretty_dio_logger/pretty_dio_logger.dart'; 8 | 9 | part 'data/auth0_client.dart'; 10 | part 'data/network/dio_wrapper.dart'; 11 | part 'data/network/exception_handler.dart'; 12 | part 'domain/telemetry.dart'; 13 | part 'domain/auth0_user.dart'; 14 | part 'errors/auth0_unauthorized_exception.dart'; 15 | part 'errors/auth_exception.dart'; 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | -------------------------------------------------------------------------------- /lib/data/network/exception_handler.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | void handleError(DioError error, JsonDecoder _decoder) { 4 | if (error.error is SocketException) 5 | throw error.error ?? SocketException("Unable to connect"); 6 | else if (error.type == DioErrorType.receiveTimeout || 7 | error.type == DioErrorType.sendTimeout || 8 | error.type == DioErrorType.connectionTimeout) { 9 | throw SocketException(error.toString()); 10 | } else { 11 | if (error.response != null) { 12 | var err = error.response?.data["error"] ?? error.response?.data['name']; 13 | var desc = error.response?.data["error_description"] ?? 14 | error.response?.data["message"] ?? 15 | error.response?.data["description"]; 16 | throw AuthException(name: err, description: desc); 17 | } else 18 | throw AuthException(description: error.error.toString()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/domain/auth0_user.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | class Auth0User { 4 | final String? accessToken; 5 | final String? refreshToken; 6 | final String? idToken; 7 | final String? scope; 8 | final DateTime? expiresDate; 9 | final String? tokenType; 10 | 11 | Auth0User.fromMap(Map snapshot) 12 | : accessToken = snapshot['access_token'], 13 | refreshToken = snapshot['refresh_token'], 14 | idToken = snapshot['id_token'], 15 | scope = snapshot['scope'], 16 | expiresDate = 17 | DateTime.now().add(Duration(seconds: snapshot['expires_in'] ?? 0)), 18 | tokenType = snapshot['token_type']; 19 | 20 | Map toJson() { 21 | return { 22 | 'access_token': accessToken, 23 | 'refresh_token': refreshToken, 24 | 'id_token': idToken, 25 | 'scope': scope, 26 | 'expires_in': expiresDate?.difference(DateTime.now()).inSeconds, 27 | 'token_type': tokenType 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mykhailo Krentsin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.2.1] - 15.05.2023. 2 | * Updated dio version and documentation 3 | 4 | ## [2.2.0-beta1] - 03.02.2022. 5 | * Removed secret from constructor, added it as passwordGrant arg (issue #12) 6 | 7 | ## [2.1.1-beta1] - 04.12.2021. 8 | * Updated documentation 9 | * Added method exchangeAppleAuthCode (issue #9) 10 | 11 | ## [2.1.0-beta1] - 02.12.2021. 12 | * Updated dependencies 13 | * Support "passwordless" via email as well as SMS (issue #6) 14 | 15 | ## [2.0.2] - 12.10.2021. 16 | * All fields in Auth0User are nullable 17 | * More documentation for classes 18 | 19 | ## [2.0.1] - 07.06.2021. 20 | * Updated dependencies and example 21 | 22 | ## [2.0.0-nullsafety.0] - 31.03.2021. 23 | * Added nullsafety support, thanks @LockedThread 24 | 25 | 26 | ## [1.3.0] - 06.01.2021. 27 | * Removed useless shared preference and token interceptor 28 | * Removed flutter as dependency 29 | * Improved documentation 30 | 31 | ## [1.2.1] - 23.09.2020. 32 | * Fixed documentation 33 | 34 | 35 | ## [1.2.0] - 23.09.2020. 36 | * Added [passwordGrant] method 37 | * Added [sendOtpCode] method for passwordless (OTP) auth 38 | * Added [verifyPhoneWithOTP] method to confirm auth via OTP 39 | * Added token interceptor for dio to automatically refresh token if needed. Tokens are saved via shared preferences 40 | * Added [Auth0UnauthorizedException] that throws when no token or it can not be refreshed 41 | 42 | ## [1.1.0] - 17.03.2020. 43 | * Fixed some methods 44 | 45 | ## [1.0.1] - 17.03.2020. 46 | * Minor file format 47 | 48 | ## [1.0.0] - 17.03.2020. 49 | * Basic set of API methods 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # auth0 2 | 3 | Dart package for authentication using Auth0 API.Contains basic set of methods like passwordRealm, sendOtp, getUser, logout etc. 4 | 5 | ## Usage 6 | 7 | ``` 8 | final Auth0Client client = Auth0Client(clientId: "abcdefg", domain: "site.url" 9 | connectTimeout: const Duration(seconds:10), sendTimeout: const Duration(seconds:10), receiveTimeout: const Duration(seconds:60), 10 | useLoggerInterceptor: true, accessToken: "abcdefg"); 11 | ``` 12 | Domain should be without https, it is added automatically 13 | 14 | ## Available methods 15 | 16 | 17 | `updateToken` - Updates current access token for Auth0 connection 18 | `authorizeUrl` - Builds the full authorize endpoint url in the Authorization Server (AS) with given parameters. 19 | `passwordRealm` - Performs Auth with user credentials using the Password Realm Grant 20 | `passwordGrant` - Performs Auth with user credentials using the Password Grant without Realm 21 | `refreshToken` - Obtains new tokens using the Refresh Token obtained during Auth (requesting offline_access scope) 22 | `getUserInfo` - Returns user information using an access token 23 | `resetPassword` - Requests an email with instructions to change password of a user 24 | `logout` - Makes logout API call 25 | `createUser` - Performs creating user with specified values 26 | `revoke` - Revokes an issued refresh token 27 | `exchange` - Exchanges a code obtained via /authorize (w/PKCE) for the user's tokens 28 | `sendOtpCode` - Performs sending sms code on phone number 29 | `verifyPhoneWithOTP` - Performs verification of phone number 30 | `exchangeAppleAuthCode1` - Exchanges a code obtained from SignIn-with-Apple social login for the user's tokens 31 | -------------------------------------------------------------------------------- /lib/data/network/dio_wrapper.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | /// Class that makes API call easier 4 | class DioWrapper { 5 | final Dio dio = Dio(); 6 | final JsonDecoder _decoder = JsonDecoder(); 7 | late String host; 8 | late String scheme; 9 | 10 | void configure(String baseUrl, Duration connectTimeout, Duration sendTimeout, 11 | Duration receiveTimeout, String accessToken, Auth0Client auth0client, 12 | {bool useLoggerInterceptor = false}) { 13 | var parsed = Uri.parse(baseUrl); 14 | scheme = parsed.scheme; 15 | host = parsed.host; 16 | 17 | dio.options 18 | ..baseUrl = baseUrl 19 | ..connectTimeout = connectTimeout 20 | ..sendTimeout = sendTimeout 21 | ..receiveTimeout = receiveTimeout; 22 | if (useLoggerInterceptor) { 23 | dio 24 | ..interceptors.add(PrettyDioLogger( 25 | requestHeader: true, 26 | requestBody: true, 27 | responseBody: true, 28 | responseHeader: true, 29 | error: true, 30 | compact: true, 31 | maxWidth: 90)); 32 | } 33 | } 34 | 35 | String encodedTelemetry() { 36 | return base64.encode(utf8.encode(jsonEncode(telemetry))); 37 | } 38 | 39 | String url(String path, {dynamic query, bool includeTelemetry = false}) { 40 | dynamic params = query ?? {}; 41 | if (includeTelemetry) { 42 | params['auth0Client'] = this.encodedTelemetry(); 43 | } 44 | var parsed = Uri( 45 | scheme: scheme, 46 | host: host, 47 | path: path, 48 | queryParameters: Map.from(params), 49 | ); 50 | return parsed.query.isEmpty 51 | ? parsed.toString().replaceAll('?', '') 52 | : parsed.toString(); 53 | } 54 | 55 | /// DIO GET 56 | /// take [url], concrete route 57 | Future get(String url, {Map? params}) async => 58 | await dio 59 | .get(url, queryParameters: params) 60 | .then((response) => response) 61 | .catchError((error) { 62 | handleError(error, _decoder); 63 | }); 64 | 65 | /// DIO POST 66 | /// take [url], concrete route 67 | Future post(String url, {body}) async => 68 | await dio.post(url, data: body).then((response) { 69 | return response; 70 | }).catchError((error) { 71 | handleError(error, _decoder); 72 | }); 73 | } 74 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | charcode: 5 | dependency: transitive 6 | description: 7 | name: charcode 8 | sha256: "8e36feea6de5ea69f2199f29cf42a450a855738c498b57c0b980e2d3cca9c362" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "1.2.0" 12 | collection: 13 | dependency: transitive 14 | description: 15 | name: collection 16 | sha256: "6d4193120997ecfd09acf0e313f13dc122b119e5eca87ef57a7d065ec9183762" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "1.15.0" 20 | dio: 21 | dependency: "direct main" 22 | description: 23 | name: dio 24 | sha256: "347d56c26d63519552ef9a569f2a593dda99a81fdbdff13c584b7197cfe05059" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "5.1.2" 28 | http_parser: 29 | dependency: transitive 30 | description: 31 | name: http_parser 32 | sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "4.0.0" 36 | meta: 37 | dependency: transitive 38 | description: 39 | name: meta 40 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.9.1" 44 | path: 45 | dependency: transitive 46 | description: 47 | name: path 48 | sha256: "2ad4cddff7f5cc0e2d13069f2a3f7a73ca18f66abd6f5ecf215219cdb3638edb" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.8.0" 52 | pretty_dio_logger: 53 | dependency: "direct main" 54 | description: 55 | name: pretty_dio_logger 56 | sha256: "00b80053063935cf9a6190da344c5373b9d0e92da4c944c878ff2fbef0ef6dc2" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | source_span: 61 | dependency: transitive 62 | description: 63 | name: source_span 64 | sha256: d5f89a9e52b36240a80282b3dc0667dd36e53459717bb17b8fb102d30496606a 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.8.1" 68 | string_scanner: 69 | dependency: transitive 70 | description: 71 | name: string_scanner 72 | sha256: dd11571b8a03f7cadcf91ec26a77e02bfbd6bbba2a512924d3116646b4198fc4 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.1.0" 76 | term_glyph: 77 | dependency: transitive 78 | description: 79 | name: term_glyph 80 | sha256: a88162591b02c1f3a3db3af8ce1ea2b374bd75a7bb8d5e353bcfbdc79d719830 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "1.2.0" 84 | typed_data: 85 | dependency: transitive 86 | description: 87 | name: typed_data 88 | sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "1.3.0" 92 | sdks: 93 | dart: ">=2.15.0 <3.0.0" 94 | -------------------------------------------------------------------------------- /lib/data/auth0_client.dart: -------------------------------------------------------------------------------- 1 | part of auth0; 2 | 3 | class Auth0Client { 4 | final DioWrapper _dioWrapper = DioWrapper(); 5 | final String clientId; 6 | final String domain; 7 | 8 | final Duration connectTimeout; 9 | final Duration sendTimeout; 10 | final Duration receiveTimeout; 11 | final bool useLoggerInterceptor; 12 | 13 | Auth0Client( 14 | {required this.clientId, 15 | required this.domain, 16 | required String accessToken, 17 | required this.connectTimeout, 18 | required this.sendTimeout, 19 | required this.receiveTimeout, 20 | this.useLoggerInterceptor = false}) { 21 | _dioWrapper.configure('https://$domain', connectTimeout, sendTimeout, 22 | receiveTimeout, accessToken, this, 23 | useLoggerInterceptor: useLoggerInterceptor); 24 | } 25 | 26 | /// Updates current access token for Auth0 connection 27 | void updateToken(String newAccessToken) { 28 | _dioWrapper.configure('https://$domain', connectTimeout, sendTimeout, 29 | receiveTimeout, newAccessToken, this); 30 | } 31 | 32 | /// Builds the full authorize endpoint url in the Authorization Server (AS) with given parameters. 33 | /// parameters [params] to send to /authorize 34 | /// @param [String] params.responseType type of the response to get from /authorize. 35 | /// @param [String] params.redirectUri where the AS will redirect back after success or failure. 36 | /// @param [String] params.state random string to prevent CSRF attacks. 37 | /// @returns [String] authorize url with specified params to redirect to for AuthZ/AuthN. 38 | /// [ref link]: https://auth0.com/docs/api/authentication#authorize-client 39 | // 40 | String authorizeUrl(dynamic params) { 41 | assert(params['redirectUri'] != null && 42 | params['responseType'] != null && 43 | params['state'] != null); 44 | var query = Map.from(params) 45 | ..addAll({ 46 | 'redirect_uri': params['redirectUri'], 47 | 'response_type': params['responseType'], 48 | 'state': params['state'], 49 | }); 50 | return _dioWrapper.url( 51 | '/authorize', 52 | query: Map.from({'client_id': this.clientId})..addAll(query), 53 | includeTelemetry: true, 54 | ); 55 | } 56 | 57 | /// Performs Auth with user credentials using the Password Realm Grant 58 | /// [clientSecret] is a secret key from auth0 account. 59 | /// [params] to send realm parameters 60 | /// @param [String] params.username user's username or email 61 | /// @param [String] params.password user's password 62 | /// @param [String] params.realm name of the Realm where to Auth (or connection name) 63 | /// @param [String] - [params.audience] identifier of Resource Server (RS) to be included as audience (aud claim) of the issued access token 64 | /// @param [String] - [params.scope] scopes requested for the issued tokens. e.g. openid profile 65 | /// @returns a [Future] with [Auth0User] 66 | /// [ref link]: https://auth0.com/docs/api-auth/grant/password#realm-support 67 | Future passwordGrant( 68 | Map params, String clientSecret) async { 69 | assert(params['username'] != null && params['password'] != null); 70 | 71 | var payload = { 72 | ...params, 73 | 'client_id': this.clientId, 74 | 'client_secret': clientSecret, 75 | 'grant_type': params['realm'] != null 76 | ? 'http://auth0.com/oauth/grant-type/password-realm' 77 | : 'password' 78 | }; 79 | 80 | Response res = await _dioWrapper.post('/oauth/token', body: payload); 81 | return Auth0User.fromMap(res.data as Map); 82 | } 83 | 84 | /// Performs Auth with user credentials using the Password Realm Grant 85 | /// [params] to send realm parameters 86 | /// @param [String] params.username user's username or email 87 | /// @param [String] params.password user's password 88 | /// @param [String] params.realm name of the Realm where to Auth (or connection name) 89 | /// @param [String] - [params.audience] identifier of Resource Server (RS) to be included as audience (aud claim) of the issued access token 90 | /// @param [String] - [params.scope] scopes requested for the issued tokens. e.g. openid profile 91 | /// @returns a [Future] with [Auth0User] 92 | /// [ref link]: https://auth0.com/docs/api-auth/grant/password#realm-support 93 | Future passwordRealm(dynamic params) async { 94 | assert(params['username'] != null && 95 | params['password'] != null && 96 | params['realm'] != null); 97 | 98 | var payload = Map.from(params) 99 | ..addAll({ 100 | 'client_id': this.clientId, 101 | 'grant_type': 'http://auth0.com/oauth/grant-type/password-realm', 102 | }); 103 | 104 | Response res = await _dioWrapper.post('/oauth/token', body: payload); 105 | return Auth0User.fromMap(res.data); 106 | } 107 | 108 | /// Performs sending sms code on phone number 109 | /// [params] to send parameters 110 | /// [connectionType] connection type to use, possible values: "sms", "email", defaults to sms 111 | /// [connectionType] send code type to use, possible: "code", "link", defaults to code 112 | /// @param [String] params.phone_number user's phone number (if using phone) 113 | /// @param [String] params.email user's email address (is using email) 114 | /// @returns a [Future] with [bool] 115 | Future sendOtpCode(dynamic params, 116 | [String? connectionType, String? send]) async { 117 | assert(params['phone_number'] != null || params['email'] != null); 118 | 119 | var payload = Map.from(params) 120 | ..addAll({ 121 | 'client_id': this.clientId, 122 | 'connection': connectionType ?? "sms", 123 | 'send': send ?? "code", 124 | "authParams": {"scope": "offline_access", "grant_type": "refresh_token"} 125 | }); 126 | 127 | await _dioWrapper.post('/passwordless/start', body: payload); 128 | return true; 129 | } 130 | 131 | /// Performs verification of phone number 132 | /// [params] to send parameters 133 | /// [realm] realm for authentication, possible values: "sms", "email", defaults to sms 134 | /// @param [String] params.otp - code form sms/email 135 | /// @param [String] params.username - users phone is sms realm or email, if email realm is being used 136 | /// @returns a [Future] with [Auth0User] 137 | Future verifyOTP(dynamic params, [String? realm]) async { 138 | assert(params['username'] != null && params['otp'] != null); 139 | 140 | var payload = Map.from(params) 141 | ..addAll({ 142 | 'client_id': this.clientId, 143 | 'realm': realm ?? "sms", 144 | 'grant_type': 'http://auth0.com/oauth/grant-type/passwordless/otp', 145 | }); 146 | 147 | Response res = await _dioWrapper.post('/oauth/token', body: payload); 148 | Auth0User user = Auth0User.fromMap(res.data); 149 | return user; 150 | } 151 | 152 | /// Obtain new tokens using the Refresh Token obtained during Auth (requesting offline_access scope) 153 | /// @param [Object] params refresh token params 154 | /// @param [String] params.refreshToken user's issued refresh token 155 | /// @param [String] - [params.scope] scopes requested for the issued tokens. e.g. openid profile 156 | /// @returns [Future] 157 | /// [ref link]: https://auth0.com/docs/tokens/refresh-token/current#use-a-refresh-token 158 | Future refreshToken(dynamic params) async { 159 | assert(params['refreshToken'] != null); 160 | var payload = Map.from(params) 161 | ..addAll({ 162 | 'refresh_token': params['refreshToken'], 163 | 'client_id': this.clientId, 164 | 'grant_type': 'refresh_token', 165 | }); 166 | var res = await _dioWrapper.post('/oauth/token', body: payload); 167 | return res.data; 168 | } 169 | 170 | /// Return user information using an access token 171 | /// Param [String] token user's access token 172 | /// Returns [Future] with user info 173 | Future getUserInfo() async { 174 | var res = await _dioWrapper.get('/userinfo'); 175 | return res.data; 176 | } 177 | 178 | /// Request an email with instructions to change password of a user 179 | /// @param [Object] parameters reset password parameters 180 | /// @param [String] parameters.email user's email 181 | /// @param [String] parameters.connection name of the connection of the user 182 | /// @returns [Future] 183 | Future resetPassword(dynamic params) async { 184 | assert(params['email'] != null && params['connection'] != null); 185 | var payload = Map.from(params)..addAll({'client_id': this.clientId}); 186 | var res = 187 | await _dioWrapper.post('/dbconnections/change_password', body: payload); 188 | return res.data; 189 | } 190 | 191 | /// Performs creating user with specified values 192 | /// @param [Object] params create user params 193 | /// @param [String] params.email user's email 194 | /// @param [String] - [params.username] user's username 195 | /// @param [String] params.password user's password 196 | /// @param [String] params.connection name of the database connection where to create the user 197 | /// @param [String] - [params.metadata] additional user information that will be stored in user_metadata 198 | /// @returns [Future] 199 | Future createUser(dynamic params, {isEmail = true}) async { 200 | if (isEmail) { 201 | assert(params['email'] != null && 202 | params['password'] != null && 203 | params['connection'] != null); 204 | } else {} 205 | var payload = Map.from(params)..addAll({'client_id': this.clientId}); 206 | if (params['metadata'] != null) 207 | payload..addAll({'user_metadata': params['metadata']}); 208 | var res = await _dioWrapper.post( 209 | '/dbconnections/signup', 210 | body: payload, 211 | ); 212 | return res.data; 213 | } 214 | 215 | /// Revoke an issued refresh token 216 | /// @param [Object] params revoke token params 217 | /// @param [String] params.refreshToken user's issued refresh token 218 | /// @returns [Future] 219 | Future revoke(dynamic params) async { 220 | assert(params['refreshToken'] != null); 221 | var payload = Map.from(params) 222 | ..addAll({ 223 | 'token': params['refreshToken'], 224 | 'client_id': this.clientId, 225 | }); 226 | var res = await _dioWrapper.post('/oauth/revoke', body: payload); 227 | return res.data; 228 | } 229 | 230 | /// Exchanges a code obtained via /authorize (w/PKCE) for the user's tokens 231 | /// [params] used to obtain tokens from a code 232 | /// @param [String] params.code code returned by /authorize. 233 | /// @param [String] params.redirectUri original redirectUri used when calling /authorize. 234 | /// @param [String] params.verifier value used to generate the code challenge sent to /authorize. 235 | /// @returns a [Future] with userInfo 236 | /// [ref link]: https://auth0.com/docs/api-auth/grant/authorization-code-pkce 237 | Future exchange(dynamic params) async { 238 | assert(params['code'] != null && 239 | params['verifier'] != null && 240 | params['redirectUri'] != null); 241 | var payload = Map.from(params) 242 | ..addAll({ 243 | 'code_verifier': params['verifier'], 244 | 'redirect_uri': params['redirectUri'], 245 | 'client_id': this.clientId, 246 | 'grant_type': 'authorization_code', 247 | }); 248 | var res = await _dioWrapper.post('/oauth/token', body: payload); 249 | return res.data; 250 | } 251 | 252 | /// Exchanges a code obtained from SignIn-with-Apple social login for the user's tokens 253 | /// @param subjectToken the auth code token issued by Sign-in-with-Apple service 254 | /// @param scope the scopes requested for the issued tokens. e.g. openid profile 255 | /// @returns a [Future] with userInfo 256 | /// [ref link]: https://auth0.com/docs/api-auth/grant/authorization-code-pkce 257 | Future exchangeAppleAuthCode( 258 | {required String subjectToken, required String scope}) async { 259 | var payload = { 260 | 'client_id': this.clientId, 261 | 'subject_token': subjectToken, 262 | "scope": scope, 263 | "grant_type": 'urn:ietf:params:oauth:grant-type:token-exchange', 264 | "subject_token_type": 265 | 'http://auth0.com/oauth/token-type/apple-authz-code', 266 | }; 267 | var res = await _dioWrapper.post('/oauth/token', body: payload); 268 | Auth0User user = Auth0User.fromMap(res.data); 269 | return user; 270 | } 271 | 272 | /// Makes logout API call 273 | /// @returns a [Future] 274 | /// [ref link]: https://auth0.com/docs/api/authentication#logout 275 | Future logout() async { 276 | Map params = Map(); 277 | params['auth0Client'] = _dioWrapper.encodedTelemetry(); 278 | var res = await _dioWrapper.get('/v2/logout', params: params); 279 | return res.data; 280 | } 281 | } 282 | --------------------------------------------------------------------------------