How to do wordpress api authentication in flutter - flutter

I am making a flutter application in which in need to fetch data from backened API which is made in wordpress.Now in postman i only need to insert client key and client secret in Oauth 1 authentication and it works fine.But in flutter application it tell that the signature data is invalid.Why ?
I followed official guide from woocommerce Api but i failed.How can i make wordpress api in flutter in dart?I am new to flutter and this is very important for me.So how can i fetch data ?Is there any method to achieve what i want ?

As per my understanding, you are looking for something like this
You want to display the products from wooCommerce using REST API.
And you want that to be done in Flutter Dart.
Auth for users.
The very first thing will do is Auth the user using Username and Password so to do that we have to do something like this
For Auth you should install the JWT plugin name JWT Authentication for
WP-API in WordPress
Then use this URL in the Flutter
Future<http.Response> login(String username, String password) async {
final http.Response response = await http.post('https://domina-name/wp-json/jwt-auth/v1/token?username=abc&password=xyz');
print(response);
return response;
}
This function fetches the data from the wooCommerce REST API endpoints and stores in the List
List<CatService> category;
Future<void> getCategoryData() async {
var res = await http.get(
"https://domain-name/wp-json/wc/v3/products/categories?per_page=100&consumer_key=xxxxxxxxxxxxxxxxxxxxx&consumer_secret=xxxxxxxxxxxxxxx&page=1");
setState(() {
var data = json.decode(res.body);
var list = data as List;
print("List of cat $list");
categoryList =
list.map<CatService>((json) => CatService.fromJson(json)).toList();
category = categoryList
.where((data) => data.count > 0 && data.catName != 'Uncategorized')
.toList();
});
}
Now you should call this future getCategoryData method like this
void initState() {
setState(() {
this.getCategoryData();
});
super.initState();
}
I have created a class for CatService
class CatService {
int catId;
String catName;
int count;
CatService({this.catId, this.catName,this.count});
factory CatService.fromJson(Map<String, dynamic> json) {
return CatService(catId: json['id'], catName: json['name'],count: json['count']);
}
}
Thanks, I hope this will help you

Related

Future provider doesn't read a riverpod state provider | Flutter

What I'm trying to do is when I log in , it takes the token from the API and update it to the riverpod state provider so the user Future provider sends a get request to the API and get the data from the API and returns it , What my API does is whenever there's a token that means user is authenticated otherwise return a Guest user so everytime I login it returns me as a Guest user because the future provider doesn't read the token state provider
Here's how the token is updated
Future<LoginResponse?> logintoDjango() async {
...
if (response.statusCode == 200) {
String userToken = responseJson['data']['token'];
await CacheHelper.setString("token", userToken);
ref.read(userTokenProvider.notifier).update((state) => userToken); //Here how it updates
...
}
That's where it returns ''
String getToken() {
final token = ref.watch(userTokenProvider);
if (token.isNotEmpty) {
return token;
}
return CacheHelper.getString("token") ?? '';
}
and that's the token provider
final userTokenProvider = StateProvider<String>((ref) => '');
and that's where it's called
final FutureProvider<UserData> userDataProvider =
FutureProvider<UserData>((ref) async {
print("Step1");
...
final token = ref.read(authHelperProvider).getToken(); //THERE
...
final response = await client.get(
url,
headers: token != '' ? {'Authorization': 'Token ${token}'} : {},
);
return UserData.fromJson(json.decode(response.body));
});
EDIT:
I tried calling
final token = ref.read(authHelperProvider).getToken(); on a different screen in the widget build and It returns the token correctly but it doesn't return it to the future provider
INFO:
CacheHelper is my Shared preferences helper class
Fixed my question after reading the documentation, I've found that It should be ref.watch instead of ref.read and it worked , Thank you so much

Need to get state data from Authentication Cubit inside another Cubit. In essence, I need to read the state

Note: I've seen similar questions all over Stackoverflow, but none of them exactly answer this.
Context:
I have an authentication cubit that has a variety of user states:
/// User exists, includes user's access and refresh tokens.
class User extends AuthenticationState {
final Tokens? tokens;
final bool justRegistered;
final bool tokensAvailable;
User({
required this.tokens,
this.justRegistered = false,
this.tokensAvailable = true,
});
#override
List<Object?> get props => [tokens, justRegistered, tokensAvailable];
}
/// No authenticated user exists.
class NoUser extends AuthenticationState {}
/// User is currently being registered or signed in.
class UserLoading extends AuthenticationState {}
Problem:
I have a Posts Cubit that needs to manage API calls and pass in the current user's access token to them in order to work. However, this access token is only stored inside the Authentication Cubit's state (in the User state, inside the tokens variable).
Is there a (good practice) way to get this token from the Authentication Cubit's User state inside the Post Cubit so I can use it to send API requests that require tokens for authentication to return posts?
Thanks!
You can create a class something like API Provider and authenticateService, pass and use in your Cubit to call API :
For example:
Future<Response<dynamic>> _callAndRetryDelete(
String url, {
int validStatus,
int retries,
}) async =>
retry(
() async {
final Map<String, String> authHeaders = await _authenticationService.getAuthHeaders;
if (authHeaders == null) {
throw ApiError('Could not get authorization', endpoint: url, method: HTTPMethod.Delete);
}
_client.options = _options(success: validStatus, authHeaders: authHeaders);
try {
return await _client.delete(url);
} on DioError catch (error) {
final String message = _error(error);
throw ApiError(message, endpoint: url, method: HTTPMethod.Delete);
}
},
maxAttempts: retries,
);
AuthenticaionService.class
Future<void> _doLogin(Map<String, dynamic> params) async {
final Response<Map<String, dynamic>> response =
await _handler.post(_loginEndpoint, body: params,
validStatus: 200);
final Map<String, String> res =
response?.data?.map((String key, dynamic value) => MapEntry<String, String>(key, value.toString()));
final Authentication authentication = Authentication.parse(res);
await _parseAndStore(authentication);
return authentication;}
AuthCubit:
Future<void> signIn() async => cubitAction(
action: () async {
emit(AuthenticationLoading());
await _authenticationService.signIn(payload);
emit(AuthenticationDone);
}
);

Why is this listener never called?

I'm trying to use Riverpod for my project, however I'm hitting some issues.
I am not sure that I'm using it very well so don't hesitate to tell me if you see anything wrong with it :)
First I have my authProvider:
final authRepoProvider = ChangeNotifierProvider.autoDispose((ref) {
return AuthRepository();
});
class AuthRepository extends ChangeNotifier {
String? token;
Future signIn(String username, String password) async {
// Do the API calls...
token = tokenReturnedByAPI;
notifyListeners();
}
}
Then I have a service, let's say it allows to fetch blog Articles, with a stream to get live update about those.
class ArticleService {
StreamController<Article> _streamCtrl;
String? _token;
API _api;
ArticleService(this._api) : _streamCtrl = StreamController<Article>() {
_api.onLiveUpdate((liveUpdate) {
_streamCtrl.add(liveUpdate);
});
}
Stream<Article> get liveUpdates => _streamCtrl.stream;
Future markArticleAsRead(String id) async {
await _api.markAsRead(_token, id);
}
}
For that article service I would like to keep the current token up to date, but I don't want to rebuild the entire service every time the token changes as there are listeners and streams being used.
For that I would prefer to listen to the changes and update it myself, like such:
final articleServiceProvider = Provider.autoDispose((ref) {
final service = ArticleService(
ref.read(apiProvider),
);
ref.listen<AuthRepository>(authRepositoryProvider, (previous, next) {
service._token = next.token;
}, fireImmediately: true);
return service;
});
That piece of code seems correct to me, however when I authenticate (authRepository.token is definitely set) and then try to invoke the markArticlesAsRead method I end up with an empty token.
The ref.listen is never called, even tho AuthRepository called notifyListeners().
I have a feeling that I'm using all that in a wrong way, but I can't really pinpoint what or where.
Try ref.watch
final articleServiceProvider = Provider.autoDispose((ref) {
final service = ArticleService(
ref.read(apiProvider),
);
final repo = ref.watch<AuthRepository>(authRepositoryProvider);
service._token = repo.token;
return service;
});

convert JSON from google app script to flutter

i'm trying to fetch data from a range of two columns on google sheet
first column with numbers,second column text
to my flutter app.
i managed to make the the http request
by this line of code:
var url = Uri.parse(
'https:`enter code here`//script.googleusercontent.com/macros/echo?user_content_key=Bzv-qcg70rUkHCr4pjI_k_qlB9c5I_GjKS-U726WCslGZ0tulYSbfdD1DabRoVrrbDSn9rIS78vQxr33OOOjaAw4d4DcA8sGm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnBqJjZp2jp3I5Qlxq6dcbGTdqr4FTByb3YAAvkZxH-A03NfLQ3Ce8hucRs86AXu4Vcg63MBXANpH4BVmytCxmg24Mg9dF6sKjQ&lib=M7v_2CxFrrqdcmzthOkMrc1jilJU4QU4H');
void getData() async {
Response response = await get(url);
if(response.statusCode == 200) {}
var feedback = convert.jsonDecode(response.body);
print('Response body: ${response.body}');
}
when i'm printing the response body,i'm getting the whole data
now,what i'm trying to do is to enter a number to a TextField in the flutter app
and to get a result from the parallel second column next to the first column where is typed the number i entered.
=============================
update
i've created a model from my json data
this the model created from the website
https://javiercbk.github.io/json_to_dart/
class Note {
late String id;
Note({required this.id});
Note.fromJson(Map<String, dynamic> json) {
id = json['id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
return data;
}
}
now this the new code for getting the data from google sheet
Future<void> getData() async {
var response = await http.get(Uri.parse(
"https://script.google.com/macros/s/AKfycbzU89ZEE0Y9sgEQZMZHSbX00M6hPdHOX6WN8IjQWa5lzgAzmAc4jZShpUfKbnJ5zm8J/exec"));
var body = response.body;
Note note = Note.fromJson(jsonDecode(body));
print(note.id.toString());
}
and i'm getting an error when trying to run the flutter app on vscode
a new tab of browser client opened no data come from the google sheet api
and this a screenshot from the vscode
While working with JSON data
The good practice is to create a model for that and then just fetch the data through the API
creating a model and a class is easy enough and doesn't take effort and makes your work easy ;)
For creating a model for your project
VISIT https://javiercbk.github.io/json_to_dart
Just copy your JSON data and paste in the textField and you will get your Model Class ready with just one click
for accessing the data
Test _test = Test.fromJson(response.body);
that's it.
refer image shown below

Auth0-How to use with Flutter

I need use Auth0 with Flutter but there is no such SDK in Auth0 site.
Auth0 works to create such SDK for Flutter.
Did anyone use Auth0 with Flutter or what can you advise?
Its very simple to get started with flutter auth0
Have a class for auth0 and call this at the places you need them. But also be sure to set the constants AUTH0_DOMAIN, AUTH0_CLIENT_ID, AUTH0_REDIRECT_URI, AUTH0_ISSUER
class Auth0 {
final FlutterAppAuth appAuth = FlutterAppAuth();
Map<String, Object> parseIdToken(String idToken) {
final List<String> parts = idToken.split('.');
assert(parts.length == 3);
return jsonDecode(
utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))));
}
Future<Map<String, Object>> getUserDetails(String accessToken) async {
const String url = 'https://$AUTH0_DOMAIN/userinfo';
final http.Response response = await http.get(
url,
headers: <String, String>{'Authorization': 'Bearer $accessToken'},
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Failed to get user details');
}
}
Future<void> loginAction() async {
isBusy = true;
errorMessage = 'Error! - ';
try {
final AuthorizationTokenResponse result =
await appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
AUTH0_CLIENT_ID,
AUTH0_REDIRECT_URI,
issuer: 'https://$AUTH0_DOMAIN',
scopes: <String>['openid', 'email', 'profile', 'offline_access'],
promptValues: ['login']
),
);
final Map<String, Object> idToken = parseIdToken(result.idToken);
final Map<String, Object> profile =
await getUserDetails(result.accessToken);
isBusy = false;
name = idToken['name'];
email = profile['email'];
picture = profile['picture'];
} on Exception catch (e, s) {
print('login error: $e - stack: $s');
isBusy = false;
errorMessage = e.toString();
}
}
Instead of using a boolean for checking isLoggedIn try saving the token in the localstorage and that will set the state as is.
There's an auth0 package for flutter to use Auth0 API provides login, logout and access APIs for authentication in your App. However, you need to make changes inside android and ios files in your flutter project. You need to configure your callbacks and application settings for that, The author has their example on github that you should check out.
I would advise you to follow the blog post provided by the Auth0 team -
Get Started with Flutter Authentication
For Flutter Web App, I am making a wrapper around Auth0 JS SPA SDK.
GitHub: https://github.com/anthonychwong/auth0-flutter-web
Pub.dev: https://pub.dev/packages/auth0_flutter_web
import 'package:auth0_flutter_web/auth0_flutter_web.dart';
Auth0 auth0 = await createAuth0Client(
Auth0CreateOptions(
domain: '-- domain of the universal login page --',
client_id: '-- id of your app --',
)
);
String token = await auth0.getTokenWithPopup();
It is in very early stage and PRs are welcome.