I am trying to do something along these lines to make an authenticated api request:
Future<http.Response> fetchAlbum() {
return http.get(
'https://jsonplaceholder.typicode.com/albums/1',
// Send authorization headers to the backend.
headers: {HttpHeaders.authorizationHeader: "Basic your_api_token_here"},
);
}
I get my api tokens by calling
FirebaseUser user = FirebaseAuth.instance.signInWithEmailAndPassword(email: _email, password: _password).
My questions are:
Don't these tokens expire after a short period of time? How do I make it so my user doesn't have to constantly log in? I don't understand this at all.
Should I save my user variable in a global provider state and access it this way?
I've been watching tons of tutorials on this and I don't get it.
Related
I am new using JWT, could someone explain to me how is the process step by step?
I am trying to validate a login and if the password is correct I receive a token with some information.
What do I do with that token in flutter? Do I decode it and use that information or what do I do?
When I make different requests, should I decode the token to do some http and then encode on the client side?
Your help would be greatly appreciated.
here is my code in flutter
// code
Future validateLogin(passwordLogin,emailLogin,BuildContext context) async {
try{
Map<String, String> headers = {
'Content-Type':'application/json;charset=UTF-8',
'Charset':'utf-8'
};
var Url= Uri.parse("http://");
var response = await http.post(Url,
body:{
'password' : passwordLogin,
'email' : emailLogin,
},
).timeout(const Duration(seconds: 90)) ;
var data = json.decode(response.body);
if(data['estado'] == "CORRECT"){
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool("CheckEstadoLogin", true);
await prefs.setString("GuardarToken", data['token'].toString());
Navigator.push(context,
new MaterialPageRoute(builder:
(context) => new MenuP())
);
}else {
Fluttertoast.showToast(
msg: "Incorrect",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16.0
);
}
}on TimeoutException catch(e){
print("Tardo mucho la conexion");
}on Error catch(e){
print("Error de Http");
}
}
}
In short, you would find that your backend(if it is indeed providing secure services and not public) will not allow you to consume any webservices unless you have a required access token. So the purpose of jwt in the authorisation flow was to obtain the same that you could have used in the subsequent API calls(mostly the access token is passed as part of the header Authorization). If the APIs you are trying to consume from the backend are public, then there is no need for the access token anyways. So it should be reverse of what you are thinking. The first part is, do you have API calls that needs to be made that will need an access token? If you do, then do the login, get the access token etc, so that it can be used when you make these API calls from your flutter app.
Flutter is the client side. The normal flow when you do a login is, to pass on your user credentials via an interface to a Identity provider in the backend which might use a LDAP or some other data source to validate the user. After which you receive a jwt token back (There can be MFA or other complex secure flows in between(refer oauth2 authorisation code? authorisation code with pkce) but the ultimate objective is to get back a access token.
Now once you have the token, the client is expected to pass this access token in all subsequent Web service calls it makes to the backend. A combination of a gateway + identity provider will ensure to validate that the access token passed for the WS is right before sending the request to the actual server which will service that web service request made by the flutter app.
Decoding jwt at client side, would also give you certain details which the client(flutter app) is already aware of, and may not be of much value.Once again there are best practices in oauth2 on how to refresh this access token on intervals by leveraging a grant etc etc.
This is a good read if you are finding the RFCs a bit complex.
https://auth0.com/docs/get-started/authentication-and-authorization-flow
What is the best practice to post data to a server, currently my database is a PostgreSql.
I would be posting to a REST Api and I want to be safe, to post I was going to use a token to verify that they are from the app but then if someone decompiles the app they will see the verification token and could then post to the API
String token = esR3bJM9bPLJoLgTesR3bJM9bPLJoLgT;
String apiUserLikes = current_server_address + "/api/user-likes/?token=$token";
final response = await http.post(
Uri.parse(apiUserLikes?token=$token),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'userID': '1234567969855478',
'UserDisplayName': 'John Jones',
'liked': 'true',
'dateLiked': '2022/12/05 00:00:00',
'eventLiked': 'Music concert at The stadium',
}),
);
What is the best way to protect users details and still post to the server
Thanks
You could never verify that the user is from the app because he can send the same request with just the command line. Even with authentication, it is still impossible to confirm. The only way to make it safe is to validate the data sent and add restriction against abuse like how many times per minute an IP/user could send data or how much could it send/download.
Instead of using static token you can use OAuth2 compliant security mechanism where token expires and new refresh token is generated/issued,
You can use firebase Auth or something like to make your App Compliant with OAuth.
For firebase Auth you can check the following link:
https://firebase.google.com/docs/auth/
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 months ago.
Improve this question
I am trying to send a http request for refresh token automatically when token expires while the user is using app. I want to refresh token in background without disturbing the application.
There are 2 ways to do this.
1.You can store access token expiry in local storage and when the access token expires then you can call an api for new access token.
Make common methods for all the rest api calls and then when token expires there is some specific response you can apply check on that and call again an api for new access token.
Future getCall({required String url}) async {
final Response response = await get(
Uri.parse(url),
headers: {
'token': await LocalStorage.getAccessToken(),
});
if (response.statusCode == 200) {
final data = json.decode(response.body);
return data;
}
else if (response.statusCode == 400 && response.body == "Token Expired")
{
await _getAcessTokenFromRefresh();
await getCall(url: url);
}
}
In addition to #Shubham choudhary answer, you can setup a Request Retrying Logic to all the HTTP requests from the app, so that any failed request gets another chance to be executed again with extra logic around it, this extra logic may be your Refresh Token Logic (The API call to refresh the token and store the new one).
If you are using http package, refer to its add-on package called http_interceptor which provides you with a mechanism for Retrying Requests with an example in the documentation for your case of token expiration:
Sometimes you need to retry a request due to different circumstances, an expired token is a really good example. Here's how you could potentially implement an expired token retry policy with http_interceptor.
class ExpiredTokenRetryPolicy extends RetryPolicy {
#override
Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async {
if (response.statusCode == 401) {
// Perform your token refresh here.
return true;
}
return false;
}
}
If you are using dio then you can do the same logic with also an add-on package called dio_smart_retry, you can refer to its documentation in pub.dev to learn more about it.
After some hours of research in vain I stay confused how to do the following:
I have a flutter app which authenticates via OAuth2 to Google (google_sign_in) and Facebook. For Facebook this is the code:
final LoginResult loginResult = await FacebookAuth.instance.login();
final userData = await FacebookAuth.instance.getUserData();
print(userData);
Which prints: {email: john.doe#email.com, id: 123456, name: John Doe}
I already have a webpage with OAuth2 authentication built in Flask/Python. Now I want my users to be able to both use Web and App and share the preferences/data/etc.
How would I achieve that? In my Flask webapp I'm just creating a user in my database if it doesn't exist and then use some authentication headers in subsequent calls. So I thought with the app I could…
send what I got from OAuth to the api and create the user if it does not yet exist
return some sort of token (with a TTL?)
verify the tokens being sent by the app
But this is a lot of custom boilerplate code, I'm sure that this is existing somewhere/somehow. Additionally: How can I be sure someone is not "tampering" my app via decompile, proxying or just plainly calls my api and claiming to be someone else?
My security requirements are medium: The app will eventually have messaging but won't be used for things like money transfer.
I'm considering these options:
PKCE but this looks like the OAuth2 flow would go through my flask api and that sounds too complex (I had a hard time already getting OAuth2 to work in flutter alone)
Resource Owner Password Credentials Grant which sounds like I can somehow pass the results of OAuth2 to my api, get back a token and use this in subsequent requests. However this seems like an outdated protocol (top google results are articles from oracle)
firebase implementation: they use the same flow: first OAuth2 authentication and then passing the credentials into their servers api. On the first time they pass the credentials a user is created and stored in the database, etc. But my reverse engineering skills are not good enough to figure out how it's done.
using a webview and use the oauth2 of my flask website. I'm shying back from this because it would be not a nice mobile experience plus I would not know how to read/store these credentials
After a lot of reading I found a good article on auth0 , in essence there are two options:
Resource Owner Password Flow - use this if you totally trust your app, e.g. when you deploy it to a closed group of users for which you have device management in place. This situation doesn't apply for me and also Auth0 doesn't recommend it. Still, it would have been relatively easy to implement.
PKCE (Proof Key for Code Exchange) - use this when the client cannot be trusted (IMO 99.9% of mobile apps). But this needs some fancy protocol between the mobile app and the server and alone by looking at the flowchart diagram I got headaches
As PKCE looks too complicated to implement myself I decided to go with Firebase, which helps small projects such as mine where you don't want to go through the pain to code the whole PKCE flow yourself.
What I did was:
adding firebase authentication to my flask app, using flask-firebase - this was worth it since it decreased the lines of python code by 40%. Because the module lacks good documentation I wrote this blog post which explains how to use it
adding firebase authentication to flutter. This is very well documented e.g. here
The whole flow then works like this:
flutter triggers the oauth flow for e.g. google
flutter gets back the auth details, including email address, name, etc. (depends on oauth provider)
the auth details are sent to firebase which creates the user if it doesn't exist yet, enriches it with a user id and packs it into an encrypted token
the token is sent to flask, which verifies the token against firebase
flask logs the user in (via flask_login) and returns a session cookie
the session cookie is stored in flutter (using requests) and used for subsequent api calls
to preserve the user logged in even after app close, the session is stored in apps preferences (using shared_preferences)
In essence, this is the code needed (google social login example):
Future<String?> signInWithGoogle() async {
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
UserCredential userCredentials =
await FirebaseAuth.instance.signInWithCredential(credential);
return userCredentials.user?.getIdToken();
}
…
var cookies = await Requests.getStoredCookies('example.com');
SharedPreferences? prefs;
if (!cookies.keys.contains('session')) {
prefs = await SharedPreferences.getInstance();
if (prefs.containsKey('session')) {
print('cookie not set, load session from prefs');
await Requests.addCookie(
'example.com', 'session', prefs.getString('session')!);
}
}
cookies = await Requests.getStoredCookies('example.com');
if (!cookies.keys.contains('session')) {
print('cookie not set, prefs contain no session, signing in');
String? idToken = await signInWithGoogle();
if (idToken != null) {
await Requests.post('https://example.com/auth/sign-in',
body: idToken,
headers: {'Content-Type': 'application/jwt'},
bodyEncoding: RequestBodyEncoding.PlainText);
var cookies = await Requests.getStoredCookies('example.com');
prefs?.setString('session', cookies['session']!.value);
}
}
var r = await Requests.get('https://example.com/api/something_which_requires_login');
The important part happens with Requests.post: this posts the idToken of firebase to flask, which in turn then verifies the token, calls login_user and returns response with the session cookie header. This cookie is stored by requests and is added to subsequent http requests.
Because this is some mouthful I created this blogpost which explains this in more detail.
I have created a login form with email, password a login button.
I am new to flutter dart and web.
I don't know how create login app using Rest API in flutter. I already have Login Rest API and its working fine on Postman using post request.
how to create login system in flutter using http post request?
This example might be helpful:Flutter: Login App using REST API and SQFLite
Basically, what it does is:
Use dart's http package to send post/get requests, encapsulated in NetworkUtil class.
RestDataSource do the login() and return a User instance.
LoginScreenPresenter defines an interface for LoginScreen view and a presenter that incorporates all business logic specific to login screen itself.
The view LoginScreen contains the login form.
Here is one method which provide authentication.
import 'package:http/http.dart' as http;
String pass='123456789'
String email='mrmodh10#gmail.com'
authenticate(String email, String pass) async {
String myurl =
"here pass your url";
http.post(myurl, headers: {
'Accept': 'application/json',
'authorization': 'pass your key(optional)'
}, body: {
"email": email,
"password": pass
}).then((response) {
print(response.statusCode);
print(response.body);
}