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
Related
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);
}
);
class User {
String token;
User({this.token});
}
class AuthService {
final String url = 'https://reqres.in/api/login';
final controller = StreamController<User>();
Future<User> signIn(String email, String password) async {
final response =
await post(url, body: {'email': email, 'password': password});
final data = jsonDecode(response.body);
final user = _userFromDatabaseUser(data);
// print(user.token);
controller.add(user);
return user;
}
//create user obj based on the database user
User _userFromDatabaseUser(Map user) {
return user != null ? User(token: user['token']) : null;
}
//user stream for provider
Stream<User> get user {
return controller.stream;
}
}
//in Sign in page
onPressed: () async {
if (_formKey.currentState.validate()) {
dynamic result = await _auth.signIn(email, password);
print(result); // Instance of 'User'
}
}
I am new to flutter and want to make an app that only authenticated users. I'm trying to read user token data from a stream. then check that token is not null if I got token then goto home page otherwise it will show error how do I print or store token value?
You can do is when you get the user after the sign In:
User result = await _auth.signIn(email, password);
Then to see the data you can do is
print(result.token);
which will give you the token, and then you can use the shared prefrences to store your token and access it.
Check out the docs for the it: https://pub.dev/packages/shared_preferences
You can override Object.toString method.
you can add this method in your User class to print the token instead of Instance of 'User'.
#override
String toString() {
// TODO: change the below return to your desired string
return "token: $token";
}
You can print using
print(userModel.toString());
I'd like to get the auth token from firebase (email and password auth) to authenticate in my firebase cloud function. It seems like the functions getIdToken() and getToken() are both not working for firebase_auth package.
is there an other function or is there even a better idea to make sure only authenticated users can trigger the cloud functions?
var token = await FirebaseAuth.instance.currentUser.getIdToken();
var response = await httpClient.get(url,headers: {'Authorization':"Bearer $token"});
I agree with #Doug on this one - callable wraps this for you and will be easier -, but my use case required me to make HTTPS calls (onRequest in Functions). Also, I think you're just in the correct path - but you're possibly not checking it in your Cloud Functions.
In your app, you'll call:
_httpsCall() async {
// Fetch the currentUser, and then get its id token
final user = await FirebaseAuth.instance.currentUser();
final idToken = await user.getIdToken();
final token = idToken.token;
// Create authorization header
final header = { "authorization": 'Bearer $token' };
get("http://YOUR_PROJECT_BASE_URL/httpsFunction", headers: header)
.then((response) {
final status = response.statusCode;
print('STATUS CODE: $status');
})
.catchError((e) {
print(e);
});
}
In your function, you'll check for the token:
export const httpsFunction = functions.https.onRequest((request, response) => {
const authorization = request.header("authorization")
if (authorization) {
const idToken = authorization.split('Bearer ')[1]
if (!idToken) {
response.status(400).send({ response: "Unauthenticated request!" })
return
}
return admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
// You can check for your custom claims here as well
response.status(200).send({ response: "Authenticated request!" })
})
.catch(err => {
response.status(400).send({ response: "Unauthenticated request!" })
})
}
response.status(400).send({ response: "Unauthenticated request!" })
})
Keep in mind:
If I'm not mistaken, those tokens are valid for 1 hour, if you are going to store them somewhere, just be aware of this. I've tested locally and it takes around 200~500ms - every time - to get only the id token, which in most cases are not that big of overhead - but is significant.
It's going to be easiest for you to use a callable function, since that lets you:
Automatically send the current user's uid in the request.
Know very easily on the function side if a UID was provided in the request, and refuse service if none was provided.
The flutter plugin is here.
You should be able to do the equivalent work yourself, though, since callable functions are just a wrapper around normal HTTP connections. It's possible for you to get the ID token of the logged in user.
import 'package:firebase_messaging/firebase_messaging.dart';
.
.
.
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
#override
Future<void> initState() {
super.initState();
_firebaseMessaging.getToken().then((token) {
assert(token != null);
print("teken is: " + token);
});
}
Get your token from firebaseAuth and put in a string.
Future<Details> getDetails() async {
String bearer = await FirebaseAuth.instance.currentUser!.getIdToken();
print("Bearer: " + bearer.toString());
String token = "Bearer ${bearer}";
var apiUrl = Uri.parse('Your url here');
final response = await http.get(apiUrl, headers: {
'Authorization' : '${token}'
});
final responseJson = jsonDecode(response.body);
return Details.fromJson(responseJson);
}
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
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.