feat: add env vars support for OAuth1 and OAuth2 authentication fields

This commit is contained in:
Udhay-Adithya
2025-08-07 10:22:43 +05:30
parent a10d44ee90
commit d33f93f784
2 changed files with 251 additions and 170 deletions

View File

@@ -1,9 +1,9 @@
import 'package:apidash/providers/settings_providers.dart';
import 'package:apidash/widgets/widgets.dart';
import 'package:apidash_core/apidash_core.dart';
import 'package:apidash_design_system/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../common_widgets.dart';
import 'consts.dart';
class OAuth1Fields extends ConsumerStatefulWidget {
@@ -25,15 +25,15 @@ class OAuth1Fields extends ConsumerStatefulWidget {
}
class _OAuth1FieldsState extends ConsumerState<OAuth1Fields> {
late TextEditingController _consumerKeyController;
late TextEditingController _consumerSecretController;
late TextEditingController _accessTokenController;
late TextEditingController _tokenSecretController;
late TextEditingController _callbackUrlController;
late TextEditingController _verifierController;
late TextEditingController _timestampController;
late TextEditingController _realmController;
late TextEditingController _nonceController;
late String _consumerKey;
late String _consumerSecret;
late String _accessToken;
late String _tokenSecret;
late String _callbackUrl;
late String _verifier;
late String _timestamp;
late String _realm;
late String _nonce;
late OAuth1SignatureMethod _signatureMethodController;
late String _addAuthDataTo;
@@ -41,20 +41,15 @@ class _OAuth1FieldsState extends ConsumerState<OAuth1Fields> {
void initState() {
super.initState();
final oauth1 = widget.authData?.oauth1;
_consumerKeyController =
TextEditingController(text: oauth1?.consumerKey ?? '');
_consumerSecretController =
TextEditingController(text: oauth1?.consumerSecret ?? '');
_accessTokenController =
TextEditingController(text: oauth1?.accessToken ?? '');
_tokenSecretController =
TextEditingController(text: oauth1?.tokenSecret ?? '');
_callbackUrlController =
TextEditingController(text: oauth1?.callbackUrl ?? '');
_verifierController = TextEditingController(text: oauth1?.verifier ?? '');
_timestampController = TextEditingController(text: oauth1?.timestamp ?? '');
_realmController = TextEditingController(text: oauth1?.realm ?? '');
_nonceController = TextEditingController(text: oauth1?.nonce ?? '');
_consumerKey = oauth1?.consumerKey ?? '';
_consumerSecret = oauth1?.consumerSecret ?? '';
_accessToken = oauth1?.accessToken ?? '';
_tokenSecret = oauth1?.tokenSecret ?? '';
_callbackUrl = oauth1?.callbackUrl ?? '';
_verifier = oauth1?.verifier ?? '';
_timestamp = oauth1?.timestamp ?? '';
_realm = oauth1?.realm ?? '';
_nonce = oauth1?.nonce ?? '';
_signatureMethodController =
oauth1?.signatureMethod ?? OAuth1SignatureMethod.hmacSha1;
_addAuthDataTo = oauth1?.parameterLocation ?? 'url';
@@ -95,21 +90,31 @@ class _OAuth1FieldsState extends ConsumerState<OAuth1Fields> {
// },
// ),
// const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _consumerKeyController,
initialValue: _consumerKey,
hintText: kHintOAuth1ConsumerKey,
infoText: kInfoOAuth1ConsumerKey,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_consumerKey = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _consumerSecretController,
initialValue: _consumerSecret,
hintText: kHintOAuth1ConsumerSecret,
infoText: kInfoOAuth1ConsumerSecret,
isObscureText: true,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_consumerSecret = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
Text(
@@ -138,61 +143,96 @@ class _OAuth1FieldsState extends ConsumerState<OAuth1Fields> {
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _accessTokenController,
initialValue: _accessToken,
hintText: kHintOAuth1AccessToken,
infoText: kInfoOAuth1AccessToken,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_accessToken = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _tokenSecretController,
initialValue: _tokenSecret,
hintText: kHintOAuth1TokenSecret,
infoText: kInfoOAuth1TokenSecret,
isObscureText: true,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_tokenSecret = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _callbackUrlController,
initialValue: _callbackUrl,
hintText: kHintOAuth1CallbackUrl,
infoText: kInfoOAuth1CallbackUrl,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_callbackUrl = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _verifierController,
initialValue: _verifier,
hintText: kHintOAuth1Verifier,
infoText: kInfoOAuth1Verifier,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_verifier = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _timestampController,
initialValue: _timestamp,
hintText: kHintOAuth1Timestamp,
infoText: kInfoOAuth1Timestamp,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_timestamp = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _nonceController,
initialValue: _nonce,
hintText: kHintOAuth1Nonce,
infoText: kInfoOAuth1Nonce,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_nonce = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _realmController,
initialValue: _realm,
hintText: kHintOAuth1Realm,
infoText: kInfoOAuth1Realm,
onChanged: (_) => _updateOAuth1(),
onChanged: (value) {
setState(() {
_realm = value;
});
_updateOAuth1();
},
),
const SizedBox(height: 16),
],
@@ -209,34 +249,34 @@ class _OAuth1FieldsState extends ConsumerState<OAuth1Fields> {
widget.authData?.copyWith(
type: APIAuthType.oauth1,
oauth1: AuthOAuth1Model(
consumerKey: _consumerKeyController.text.trim(),
consumerSecret: _consumerSecretController.text.trim(),
accessToken: _accessTokenController.text.trim(),
tokenSecret: _tokenSecretController.text.trim(),
consumerKey: _consumerKey.trim(),
consumerSecret: _consumerSecret.trim(),
accessToken: _accessToken.trim(),
tokenSecret: _tokenSecret.trim(),
signatureMethod: _signatureMethodController,
parameterLocation: _addAuthDataTo,
callbackUrl: _callbackUrlController.text.trim(),
verifier: _verifierController.text.trim(),
timestamp: _timestampController.text.trim(),
nonce: _nonceController.text.trim(),
realm: _realmController.text.trim(),
callbackUrl: _callbackUrl.trim(),
verifier: _verifier.trim(),
timestamp: _timestamp.trim(),
nonce: _nonce.trim(),
realm: _realm.trim(),
credentialsFilePath: credentialsFilePath,
),
) ??
AuthModel(
type: APIAuthType.oauth1,
oauth1: AuthOAuth1Model(
consumerKey: _consumerKeyController.text.trim(),
consumerSecret: _consumerSecretController.text.trim(),
accessToken: _accessTokenController.text.trim(),
tokenSecret: _tokenSecretController.text.trim(),
consumerKey: _consumerKey.trim(),
consumerSecret: _consumerSecret.trim(),
accessToken: _accessToken.trim(),
tokenSecret: _tokenSecret.trim(),
signatureMethod: _signatureMethodController,
parameterLocation: _addAuthDataTo,
callbackUrl: _callbackUrlController.text.trim(),
verifier: _verifierController.text.trim(),
timestamp: _timestampController.text.trim(),
nonce: _nonceController.text.trim(),
realm: _realmController.text.trim(),
callbackUrl: _callbackUrl.trim(),
verifier: _verifier.trim(),
timestamp: _timestamp.trim(),
nonce: _nonce.trim(),
realm: _realm.trim(),
credentialsFilePath: credentialsFilePath,
),
),

View File

@@ -4,12 +4,12 @@ import 'package:apidash/providers/settings_providers.dart';
import 'package:apidash/providers/collection_providers.dart';
import 'package:apidash/models/models.dart';
import 'package:apidash/utils/file_utils.dart';
import 'package:apidash/widgets/field_auth.dart';
import 'package:apidash_core/apidash_core.dart';
import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:timeago/timeago.dart' as timeago;
import '../common_widgets.dart';
import 'consts.dart';
class OAuth2Fields extends ConsumerStatefulWidget {
@@ -28,19 +28,19 @@ class OAuth2Fields extends ConsumerStatefulWidget {
class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
late OAuth2GrantType _grantType;
late TextEditingController _authorizationUrlController;
late TextEditingController _accessTokenUrlController;
late TextEditingController _clientIdController;
late TextEditingController _clientSecretController;
late TextEditingController _redirectUrlController;
late TextEditingController _scopeController;
late TextEditingController _stateController;
late String _authorizationUrl;
late String _accessTokenUrl;
late String _clientId;
late String _clientSecret;
late String _redirectUrl;
late String _scope;
late String _state;
late String _codeChallengeMethod;
late TextEditingController _usernameController;
late TextEditingController _passwordController;
late TextEditingController _refreshTokenController;
late TextEditingController _identityTokenController;
late TextEditingController _accessTokenController;
late String _username;
late String _password;
late String _refreshToken;
late String _identityToken;
late String _accessToken;
DateTime? _tokenExpiration;
@override
@@ -48,25 +48,18 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
super.initState();
final oauth2 = widget.authData?.oauth2;
_grantType = oauth2?.grantType ?? OAuth2GrantType.authorizationCode;
_authorizationUrlController =
TextEditingController(text: oauth2?.authorizationUrl ?? '');
_accessTokenUrlController =
TextEditingController(text: oauth2?.accessTokenUrl ?? '');
_clientIdController = TextEditingController(text: oauth2?.clientId ?? '');
_clientSecretController =
TextEditingController(text: oauth2?.clientSecret ?? '');
_redirectUrlController =
TextEditingController(text: oauth2?.redirectUrl ?? '');
_scopeController = TextEditingController(text: oauth2?.scope ?? '');
_stateController = TextEditingController(text: oauth2?.state ?? '');
_usernameController = TextEditingController(text: oauth2?.username ?? '');
_passwordController = TextEditingController(text: oauth2?.password ?? '');
_refreshTokenController =
TextEditingController(text: oauth2?.refreshToken ?? '');
_identityTokenController =
TextEditingController(text: oauth2?.identityToken ?? '');
_accessTokenController =
TextEditingController(text: oauth2?.accessToken ?? '');
_authorizationUrl = oauth2?.authorizationUrl ?? '';
_accessTokenUrl = oauth2?.accessTokenUrl ?? '';
_clientId = oauth2?.clientId ?? '';
_clientSecret = oauth2?.clientSecret ?? '';
_redirectUrl = oauth2?.redirectUrl ?? '';
_scope = oauth2?.scope ?? '';
_state = oauth2?.state ?? '';
_username = oauth2?.username ?? '';
_password = oauth2?.password ?? '';
_refreshToken = oauth2?.refreshToken ?? '';
_identityToken = oauth2?.identityToken ?? '';
_accessToken = oauth2?.accessToken ?? '';
_codeChallengeMethod = oauth2?.codeChallengeMethod ?? 'sha-256';
// Load credentials from file if available
@@ -84,19 +77,19 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
final Map<String, dynamic> decoded = jsonDecode(credentials);
setState(() {
if (decoded['refreshToken'] != null) {
_refreshTokenController.text = decoded['refreshToken']!;
_refreshToken = decoded['refreshToken']!;
} else {
_refreshTokenController.text = "N/A";
_refreshToken = "N/A";
}
if (decoded['idToken'] != null) {
_identityTokenController.text = decoded['idToken']!;
_identityToken = decoded['idToken']!;
} else {
_identityTokenController.text = "N/A";
_identityToken = "N/A";
}
if (decoded['accessToken'] != null) {
_accessTokenController.text = decoded['accessToken']!;
_accessToken = decoded['accessToken']!;
} else {
_accessTokenController.text = "N/A";
_accessToken = "N/A";
}
// Parse expiration time
if (decoded['expiration'] != null) {
@@ -163,64 +156,94 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
kVSpacer16,
if (_shouldShowField(OAuth2Field.authorizationUrl))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _authorizationUrlController,
initialValue: _authorizationUrl,
hintText: kHintOAuth2AuthorizationUrl,
infoText: kInfoOAuth2AuthorizationUrl,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_authorizationUrl = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.username))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _usernameController,
initialValue: _username,
hintText: kHintOAuth2Username,
infoText: kInfoOAuth2Username,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_username = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.password))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _passwordController,
initialValue: _password,
hintText: kHintOAuth2Password,
infoText: kInfoOAuth2Password,
isObscureText: true,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_password = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.accessTokenUrl))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _accessTokenUrlController,
initialValue: _accessTokenUrl,
hintText: kHintOAuth2AccessTokenUrl,
infoText: kInfoOAuth2AccessTokenUrl,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_accessTokenUrl = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.clientId))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _clientIdController,
initialValue: _clientId,
hintText: kHintOAuth2ClientId,
infoText: kInfoOAuth2ClientId,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_clientId = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.clientSecret))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _clientSecretController,
initialValue: _clientSecret,
hintText: kHintOAuth2ClientSecret,
infoText: kInfoOAuth2ClientSecret,
isObscureText: true,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_clientSecret = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.codeChallengeMethod)) ...[
@@ -254,32 +277,47 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
],
if (_shouldShowField(OAuth2Field.redirectUrl))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _redirectUrlController,
initialValue: _redirectUrl,
hintText: kHintOAuth2RedirectUrl,
infoText: kInfoOAuth2RedirectUrl,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_redirectUrl = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.scope))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _scopeController,
initialValue: _scope,
hintText: kHintOAuth2Scope,
infoText: kInfoOAuth2Scope,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_scope = value;
});
_updateOAuth2();
},
),
),
if (_shouldShowField(OAuth2Field.state))
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _stateController,
initialValue: _state,
hintText: kHintOAuth2State,
infoText: kInfoOAuth2State,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_state = value;
});
_updateOAuth2();
},
),
),
..._buildFieldWithSpacing(
@@ -291,33 +329,48 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
Divider(),
kVSpacer16,
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _refreshTokenController,
initialValue: _refreshToken,
hintText: kHintOAuth2RefreshToken,
infoText: kInfoOAuth2RefreshToken,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_refreshToken = value;
});
_updateOAuth2();
},
),
),
..._buildFieldWithSpacing(
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _identityTokenController,
initialValue: _identityToken,
hintText: kHintOAuth2IdentityToken,
infoText: kInfoOAuth2IdentityToken,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_identityToken = value;
});
_updateOAuth2();
},
),
),
..._buildFieldWithSpacing(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AuthTextField(
EnvAuthField(
readOnly: widget.readOnly,
controller: _accessTokenController,
initialValue: _accessToken,
hintText: kHintOAuth2AccessToken,
infoText: kInfoOAuth2AccessToken,
onChanged: (_) => _updateOAuth2(),
onChanged: (value) {
setState(() {
_accessToken = value;
});
_updateOAuth2();
},
),
if (_tokenExpiration != null) ...[
const SizedBox(height: 4),
@@ -387,22 +440,22 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
final updatedOAuth2 = AuthOAuth2Model(
grantType: _grantType,
authorizationUrl: _authorizationUrlController.text.trim(),
clientId: _clientIdController.text.trim(),
accessTokenUrl: _accessTokenUrlController.text.trim(),
clientSecret: _clientSecretController.text.trim(),
authorizationUrl: _authorizationUrl.trim(),
clientId: _clientId.trim(),
accessTokenUrl: _accessTokenUrl.trim(),
clientSecret: _clientSecret.trim(),
credentialsFilePath: credentialsFilePath != null
? "$credentialsFilePath/oauth2_credentials.json"
: null,
codeChallengeMethod: _codeChallengeMethod,
redirectUrl: _redirectUrlController.text.trim(),
scope: _scopeController.text.trim(),
state: _stateController.text.trim(),
username: _usernameController.text.trim(),
password: _passwordController.text.trim(),
refreshToken: _refreshTokenController.text.trim(),
identityToken: _identityTokenController.text.trim(),
accessToken: _accessTokenController.text.trim(),
redirectUrl: _redirectUrl.trim(),
scope: _scope.trim(),
state: _state.trim(),
username: _username.trim(),
password: _password.trim(),
refreshToken: _refreshToken.trim(),
identityToken: _identityToken.trim(),
accessToken: _accessToken.trim(),
);
widget.updateAuth?.call(
@@ -423,9 +476,9 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
await deleteFileFromPath(credentialsFilePath);
}
setState(() {
_refreshTokenController.text = "";
_accessTokenController.text = "";
_identityTokenController.text = "";
_refreshToken = "";
_accessToken = "";
_identityToken = "";
_tokenExpiration = null;
});
}
@@ -455,18 +508,6 @@ class _OAuth2FieldsState extends ConsumerState<OAuth2Fields> {
@override
void dispose() {
_authorizationUrlController.dispose();
_accessTokenUrlController.dispose();
_clientIdController.dispose();
_clientSecretController.dispose();
_redirectUrlController.dispose();
_scopeController.dispose();
_stateController.dispose();
_usernameController.dispose();
_passwordController.dispose();
_refreshTokenController.dispose();
_identityTokenController.dispose();
_accessTokenController.dispose();
super.dispose();
}
}