Dart / flutter login Post request - flutter

I'm trying to log in on this forum, I tried several ways (Dio, Requests ) without result.
I tested it with postman using other languages ​​and libraries (like curl, python, node) and it works like a charm.
[EDIT]
Ok finally got it!
once logged in, the server returns the status code 303.
and since followredirects is set to true by default, a new request was made without session cookies.
That's why I never found the session cookie in the response header.
A method similar to "history" from lib python requests would be great here.
new:
import 'package:http/http.dart';
void main() async {
final request = new Request(
'POST', Uri.parse('https://xenforo.com/community/login/login'))
..headers.addAll({"Content-Type": "application/x-www-form-urlencoded"})
..bodyFields = {'login':'myuser',
'password': 'mypass'}
..followRedirects = false; // don't follow the damn 303 code if you're not
// going to set the cookies automatically.
final response = await request.send();
print(response.statusCode); // 303 redirected successfully logged in!
print(response.headers); // session token: xf_session=oisufhisuefhsef...
}
or
import 'dart:io';
void main() async {
final client = HttpClient();
final request = await
client.postUrl(Uri.parse("https://xenforo.com/community/login/login"));
request.headers.set(HttpHeaders.contentTypeHeader, "application/x-www_form-urlencoded");
request.followRedirects = false;
request.write("login=myusername&password=mypass");
final response = await request.close();
print(response.statusCode);
print(response.headers);
}

You should either use await or then, try the following code:
import 'package:http/http.dart' as http;
void main() {
http.get("https://xenforo.com/community/").then((response) {
var ls = response.headers['set-cookie'].split(';');
final cookie = ls[0] + '; ' + ls[5].split(',')[1];
login(cookie);
});
}
void login(String cookie) {
http.post("https://xenforo.com/community/login/login/", headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': cookie
}, body: {
'login': 'myusernam',
'password': 'mypass'
}).then((response) {
print(response.statusCode);
print(response.body);
});
}

ok finally got it Every time the login was successful, the request was automatically redirected without the session cookies. FollowRedirects need set to false to work properly and http.post does not have this option.
A method similar to the "history" of lib python requests would be great.

Related

Why is my flutter app not handling Spotify's API authorization after signing in?

I'm making a flutter app using Spotify's API. I have a basic homepage that uses a button to launch a browser to login to Spotify. Here is my backend code:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uni_links/uni_links.dart';
class SpotifyAuth with ChangeNotifier {
final String CLIENT_ID = "My client ID";
final String ClIENT_SECRET = "My client secret";
final String REDIRECT_URI = "http://localhost:8000/callback";
final String SCOPE = 'user-read-private user-read-email';
// var state = 'your-state';
late String _accessToken;
late String _refreshToken;
Uri createAuthenticationUri(){
var query = [
'response_type=code',
'client_id=$CLIENT_ID',
'scope=${Uri.encodeComponent(SCOPE)}',
'redirect_uri=${Uri.encodeComponent(REDIRECT_URI)}',
];
var queryString = query.join('&');
var url = 'https://accounts.spotify.com/authorize?' + queryString;
var parsedUrl = Uri.parse(url);
return parsedUrl;
}
Future<void> launchInBrowser() async {
if (!await launchUrl(
createAuthenticationUri(),
mode: LaunchMode.externalApplication,
)){
throw Exception('Could not launch Url');
}
}
Future<void> launchAuth() async {
await launchInBrowser();
await initUniLinks();
}
Future<void> getAccessToken(String code) async {
var body = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
"client_id": CLIENT_ID,
"client_secret": ClIENT_SECRET
};
// Create a request header with the required information
var header = {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization":
"Basic ${base64Encode(utf8.encode("$CLIENT_ID:$ClIENT_SECRET>"))}"
};
// Send the request to the Spotify token endpoint
var response = await http.post(
Uri.parse("https://accounts.spotify.com/api/token"),
body: body,
headers: header);
// Check if the request was successful
if (response.statusCode == 200) {
// Parse the JSON response
var data = json.decode(response.body);
// Get the access token from the response
String accessToken = data["access_token"];
// Store the access token for future use
// ...
_accessToken = accessToken;
} else {
print("Error");
}
}
Future<void> initUniLinks() async {
// Get the latest initial link
String? initialLink = await getInitialLink();
// Check if the link contains a Spotify authorization code
if (initialLink != null && initialLink.contains("code=")) {
// Extract the code from the link
String code = initialLink.split("code=")[1];
// Use the code to get an access token from Spotify
getAccessToken(code);
}
else{
print("Nothing");
}
}
}
My redirect URI is set in the spotify dashboard.
My app widget calls luanchAuth();
and then it should wait for the authentication code with initUniLinks() but it seems like initUniLinks() executes immediately without waiting for the authentication. When I authenticate in Spotify, it throws a generic "can't connect to localhost" error page but the url includes the auth code that I need.
Not sure what I'm doing wrong here. Admittedly I'm new to Oauth and app-api-connections in general but I thought this would work.
REDIRECT URI is the problem here, You cannot have redirect URI with localhost it fails. either use ngrok and provide the mapped https url or host your callback url and provide it.
Use the custom scheme for redirect_uri, something like this my-app://token/callback. See App Settings for Spotify rules.
Then configure the application for Deep Linking to receive the authentication response.

api calls - Flutter

I'm trying to make a api call but I can't success, everything goes fine until the call, and there stop everything and the function finish, what I do wrong?
Future<String> get() async {
var url = Uri.parse("https://10.0.2.2:7021/api/Auth/login");
var headers = {"content-type": "application/json"};
final msg = jsonEncode(
{"username": "string", "password": "string", "email": "string"});
var response = await http!.post(url, body: msg, headers: headers);
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
print("Correct");
return "Correct";
} else {
print(response.statusCode);
print("User not allowed");
throw Exception("User not allowed");
}
}
Mistake comes here
debug window
You have probably imported the "wrong" http. Do it like that:
import 'package:http/http.dart' as http;
You dont need to write http! because http is a package and is never null and since you are doing http! I guess you imported something wrong in your code.
EDIT:
Maybe your device can't reach 10.0.2.2 (or that port), you should set a timeout to find it out fast:
http.post(url, body: msg, headers: headers).timeout(
const Duration(seconds: 3),
onTimeout: () {
// request timed out
return http.Response('Error', 408);
},
);
Have you imported http package like this?
import 'package:http/http.dart' as http;
And use case like this
var response = await http.post(url, body: msg, headers: headers);
add .php to login in the url :
https://10.0.2.2:7021/api/Auth/login.php
if you are working with php
or .py for python

Flutter REST Calls Time Out

I am making api calls via flutter to my server. I have checked my android manifest settings and I have placed
<uses-permission android:name="android.permission.INTERNET"/>
But, the api calls time out. Here is my call:
Future driverLogin(userdetails) async {
var url = 'http://$_server/api/token/';
print(userdetails.values);
await http.post(url, body: json.encode(userdetails), headers: {
"Content-Type": "application/json"
}).then((http.Response response) {
print(response.body);
final Map<String, dynamic> responseData = json.decode(response.body);
Token tkn = Token.fromJSON(responseData);
_accessTkn = tkn.access;
_refreshTkn = tkn.refresh;
print('Refreshingly refreshed ${tkn.refresh}');
if (response.statusCode == 200) {
addToken(_accessTkn);
addRefresh(_refreshTkn);
print(responseData);
// tokenType = 'email';
print('Signed In');
// preformLogin();
} else {
// popupSwitch(2);
print('Error Could not sign in');
}
});
return _accessTkn;
}
When I run it I get this error:
Bad state: Insecure HTTP is not allowed by platform:
make sure to import like this.
import 'package:http/http.dart' as http;
and make your url like this.
var url = 'https://$_server/api/token/';
Also check this links maybe will help you
https://flutter.dev/docs/release/breaking-changes/network-policy-ios-android
https://medium.com/flutter-community/solving-the-new-https-requirements-in-flutter-7abe240fbf23

How to make API call in flutter with header key?

Suppose the host site is: :
https://dev.xyz.com
API header key: "x-api-key: 7462-3172-8773-3312-5819"
To register a new user you have to call PUT method: {{host}}/api/customer/
And the body is like this:
{"email": "test#example.net",
"password": "aabbccdd",
"Name": "John",
}
Now how do I accomplish this in flutter? I have searched through several tutorials and still in confusion.
Import the http package from dart library and alias it as http, reason for this aliasing is that you dont want to have .get() method suggestion everywhere in the file. So when you use it with http as http.get() it will give you suggestion for get, In which you can pass the parameter called headers.
Code goes as follows:
import 'package:http/http.dart' as http;
url = 'YOUR_URL';
var response = await http.get(
url,
headers: {HttpHeaders.authorizationHeader: TOKEN}, //an example header
);
In your case,
import 'dart:convert';
import 'dart:io';
import 'dart:async';
main() async {
String url =
'https://dev.xyz.com';
Map map = {
'data': {'apikey': '7462-3172-8773-3312-5819'},
};
print(await apiRequest(url, map));
}
Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
// todo - you should check the response.statusCode
String reply = await response.transform(utf8.decoder).join();
httpClient.close();
return reply;
}
You need put the header on the http request. For example:
await put(urlApi + 'update/'+ customer.id, headers: {'token': token, 'content-type': 'application/json'},body: body);

How to get the token from firebase_auth

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);
}