I need to make a request to my firebase rtdb from my shelf server hosted on 127.0.0.1, I have the url and the db secrets. But whenever i try to make a get request to the db url using the http package, i get a 401 error.
My code:
import 'dart:io';
import 'package:http/http.dart';
import 'package:firebase/firebase_io.dart';
class FirebaseLocalClient {
void putSudokuBoard() async {
var a = await get(
Uri.parse(
"<db url>"),
headers: {
"Authorization": "Bearer <your database secret>",
'Content-Type': "application/js"
});
print(a.statusCode);
//print(a.runtimeType);
}
}
void main(List<String> args) {
FirebaseLocalClient().putSudokuBoard();
}
I call this code from a shelf server(similar to the code in main function), but running it here itself recieves a 401 error.
I am not able to understand why i am recieving a 401 error, i have the db secrets and yet i am unable to get the data at that location. I tried using the admin sdk json but recieved 401 on that too
The output when i use a.body:
The output when i use a.statuscode:
If you are using the db secrets, it looks like you need to append the auth param.
per https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-uri-params
curl 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'
Remove the Authorization header and try it in curl
Related
I have a Jetty http server with some Jersey rest services. Those services are called from a React website that runs on a Node server.
Due to the cross origin nature of this setup, I had to add some HTTP headers. Basically, all my webservices return a createOkResult() which is created as follows.
#POST
#Path("orders/quickfilter")
#Consumes(MediaType.APPLICATION_JSON)
public Response getQuickFilterProductionOrders(String data)
{
...
return createOkResult(json.toString());
}
protected Response createOkResult(Object result)
{
return buildCrossOrigin(Response.ok().entity(result));
}
protected static Response buildCrossOrigin(Response.ResponseBuilder responseBuilder)
{
return responseBuilder.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS")
.build();
}
For the #GET webservices that works fine. But when I create an #POST service, I just can't get it working.
Webbrowsers (chrome and firefox) return these kind of errors:
Access to XMLHttpRequest at 'http://localhost:59187/rs/production/orders/quickfilter' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
So, at first sight I would be tempted to think that the headers are still missing. The thing is, when I test this service with a tool like Postman, then all headers turn out to be in place, and the service even returns the requested data.
This is a screenshot of a POST request.
From my front-end (which runs on the node server), I use the axios API, which uses promises, and my request looks like this:
const url = "http://localhost:59187/rs/production/orders/quickfilter";
const data = JSON.stringify(request);
const headers = { headers: { "Content-Type": "application/json" } };
const promise = axios.post(url, data, headers);
Right now I have a HTTP error 500, If I remove the content type header, I get an unsupported media exception. So, I have reasons to believe that the content type is ok.
Paul Samsotha pointed me in the right direction.
I ended up adding a filter to the ServletContextHandler. Unlike the linked article, I didn't really have to create that filter from scratch. There was an existing filter class that I could use: i.e. org.eclipse.jetty.servlets.CrossOriginFilter.
FilterHolder filterHolder = context.addFilter(CrossOriginFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
filterHolder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");
Some of the above parameters can probably be left out, as they are default values. But what appeared to be crucial for me, was to set the CHAIN_PREFLIGHT_PARAM to false.
One nice side-effect, is that I can simplify the code of the actual services. They do not longer need to add special headers, by contrast they can now just return Response.ok().entity(result).build();.
I am trying to send a post request to receive my access token from https://login.microsoftonline.com/common/oauth2/v2.0/token. When I tried this in my REST client, it works, but when I try to integrate it to my app, it sends me a error 400 Bad Gateway, with the message AADSTS90014: The request body must contain the following parameter: 'grant_type'. I tried searching for answers, and found out that I need to implement headers in my post request, so I did that, but it still won't work. Any ideas?
Http Imports:
import { HttpClient, HttpHeaders, HttpRequest } from '#angular/common/http';
Call to post request:
var url=this.outlook_authentification_endpoint+"token";
var query_parameters=JSON.stringify({grant_type:"authorization_code", client_id:this.outlook_client_id, code: this.outlook_user_code, client_secret: this.outlook_secret_key, redirect_uri: this.outlook_redirect_uri});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
this.query_service.postOutlook(url, query_parameters, httpOptions, (data)=>
{
console.log(data);
});
Call to the post function:
public postOutlook(url, query, headers, callback)
{
this.operation_pending=true;
this.http_client.post(url,query, headers).subscribe((data)=>
{
this.operation_pending=false;
callback(data);
});
}
Can anyone see where my error is?
You are using wrong OAuth2 flow (the way of getting tokens). You are using the Auth code grant, which cannot be used in browser applications, because you would have to keep your client secret in JavaScript, which means make it public. So you cannot access the /token endpoint either.
You should use the Implicit grant, which is designed for browser applications. Then you get tokens right into your Angular application without the need of going to the /token endpoint.
I'm trying to implementing a proxy server with Dart: a web app running on the browser makes a request to my dart server app (proxy server) running locally, and then the proxy server makes a request to the external server. I then add CORS headers to the response that is going to be sent back to the client (web app).
Here's how I implemented the proxy server:
import 'dart:io';
import 'dart:convert';
main() async {
var server = await HttpServer.bind(InternetAddress.ANY_IP_V6, 8080);
print('Server listening on port ${server.port}...');
var client = 0;
HttpClient proxy;
await for (HttpRequest request in server) {
print('Request received from client ${++client}.');
// Adds CORS headers.
request.response.headers.add('Access-Control-Allow-Origin', '*');
proxy = new HttpClient()
..getUrl(Uri.parse('http://example.com/'))
// Makes a request to the external server.
.then((HttpClientRequest proxyRequest) => proxyRequest.close())
// Sends the response to the web client.
.then((HttpClientResponse proxyResponse) =>
proxyResponse.transform(UTF8.decoder).listen((contents) =>
request.response
..write(contents)
..close()
));
print('Response sent to client $client.');
}
}
This works fine most of the times, but sometimes the client only receives part of the response. I think sometimes the request.response.close() is being executed before the request.response.write(contents) finished executing, and so the response is sent before it has finished writing the contents.
Is there any way to solve this and only send the response once the contents have been written? Thanks.
You close the response after you receive the first chunk of data (..close()) . You should remove the close() from there and listen to the close event of the proxyResponse stream and close the response from there.
Given the following pseudo code:
import "dart:html";
HttpRequest.postFormData(url, data).then((HttpRequest request) {
...
}).catchError((error) {
// How do I get the response text from here?
});
If the web server replies with a 400 BAD REQUEST then the catchError will be invoked. However, the error parameter is of the type _XMLHttpRequestProgressEvent which apparently doesn't exist in Dart's library.
So, how do I get the response text from the 400 BAD REQUEST response that was sent from the web server?
It seems like the target in your error object is actually your HttpRequest.
You may find this link helpful: https://www.dartlang.org/docs/tutorials/forms/#handling-post-requests
You could do something like:
import "dart:html";
HttpRequest.postFormData(url, data).then((HttpRequest request) {
request.onReadyStateChange.listen((response) => /* do sth with response */);
}).catchError((error) {
print(error.target.responseText); // Current target should be you HttpRequest
});
Is there any way to accept POST type requests without using Nerve lib in Node.js?
By default the http.Server class of Node.js accepts any http method.
You can get the method using request.method (api link).
Example:
var sys = require('sys'),
http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write(request.method);
response.end();
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/');
This will create a simple http server on the port 8000 that will echo the method used in the request.
If you want to get a POST you should just check the request.method for the string "POST".
Update regarding response.end:
Since version 0.1.90, the function to close the response is response.end instead of response.close. Besides the name change, end can also send data and close the response after this data is sent unlike close. (api example)