I have a couchdb server, which at this moment is for development and it has just one node running in docker.
I would like to authenticate through JWT. I have build my token.
GET https://comp010:6984/_session
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: Bearer <JWT token>
I get proper answer (or at least I think so):
{
"ok": true,
"userCtx": {
"name": "uaru",
"roles": "admin"
},
"info": {
"authentication_handlers": [
"jwt",
"cookie",
"default"
],
"authenticated": "jwt"
}
}
When I send request to get actual object from the database
GET https://comp010:6984/db_userspaces/xxxx3
Accept: application/json
Content-Type: application/json; charset=utf-8
I get "unauthorized" exception. This is ok, I did not authenticated this request. So I add the same authorization header:
GET https://comp010:6984/db_userspaces/xxxx3
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: Bearer <JWT token>
And I get
{
"error": "internal_server_error",
"reason": "No DB shards could be opened.",
"ref": 179462285
}
But if I switch off the authorization ( [chttpd] require_valid_user = false), and send the same request without Authorization header,
GET https://comp010:6984/db_userspaces/xxxx3
Accept: application/json
Content-Type: application/json; charset=utf-8
I get proper response.
Server: CouchDB/3.2.1 (Erlang OTP/23)
X-Couch-Request-ID: 02c628ce15
X-CouchDB-Body-Time: 0
{
"_id": "xxxx3",
"_rev": "1-a11f390ffa77a03c557ffbbc7c5fda75",
"x": "1"
}
How JWT can relate to shards? I am puzzled and I cannot find anything related.
There are no errors with Fauxton.
Thank you in advance for any suggestions.
Here is the log when the request took place
couchdb-server_1 | [error] 2022-03-09T04:52:34.662593Z nonode#nohost <0.6234.1> 82a6b79f38 rexi_server: from: nonode#nohost(<0.6134.1>) mfa: fabric_rpc:open_shard/2 error:function_clause [{lists,usort,[<<"admin">>],[{file,"lists.erl"},{line,1063}]},{couch_db,check_security,3,[{file,"src/couch_db.erl"},{line,713}]},{couch_db,is_authorized,2,[{file,"src/couch_db.erl"},{line,705}]},{couch_db,is_member,1,[{file,"src/couch_db.erl"},{line,685}]},{couch_db,check_is_member,1,[{file,"src/couch_db.erl"},{line,671}]},{couch_db,open,2,[{file,"src/couch_db.erl"},{line,166}]},{mem3_util,get_or_create_db,2,[{file,"src/mem3_util.erl"},{line,549}]},{fabric_rpc,open_shard,2,[{file,"src/fabric_rpc.erl"},{line,307}]}]
couchdb-server_1 | [error] 2022-03-09T04:52:34.662982Z nonode#nohost <0.6236.1> 82a6b79f38 rexi_server: from: nonode#nohost(<0.6134.1>) mfa: fabric_rpc:open_shard/2 error:function_clause [{lists,usort,[<<"admin">>],[{file,"lists.erl"},{line,1063}]},{couch_db,check_security,3,[{file,"src/couch_db.erl"},{line,713}]},{couch_db,is_authorized,2,[{file,"src/couch_db.erl"},{line,705}]},{couch_db,is_member,1,[{file,"src/couch_db.erl"},{line,685}]},{couch_db,check_is_member,1,[{file,"src/couch_db.erl"},{line,671}]},{couch_db,open,2,[{file,"src/couch_db.erl"},{line,166}]},{mem3_util,get_or_create_db,2,[{file,"src/mem3_util.erl"},{line,549}]},{fabric_rpc,open_shard,2,[{file,"src/fabric_rpc.erl"},{line,307}]}]
couchdb-server_1 | [error] 2022-03-09T04:52:34.663440Z nonode#nohost <0.6134.1> 82a6b79f38 req_err(179462285) internal_server_error : No DB shards could be opened.
couchdb-server_1 | [<<"fabric_util:get_shard/4 L118">>,<<"fabric_util:get_shard/4 L132">>,<<"fabric:get_security/2 L183">>,<<"chttpd_auth_request:db_authorization_check/1 L112">>,<<"chttpd_auth_request:authorize_request/1 L19">>,<<"chttpd:handle_req_after_auth/2 L325">>,<<"chttpd:process_request/1 L310">>,<<"chttpd:handle_request_int/1 L249">>]
couchdb-server_1 | [notice] 2022-03-09T04:52:34.663753Z nonode#nohost <0.6134.1> 82a6b79f38 comp010:6984 ::ffff:150.26.121.46 uaru GET /db_userspaces/xxxx3 500 ok 2
In the payload to be turned into JWT, roles MUST BE an array.
{
:sub => username,
:'_couchdb.roles' => roles,
:exp => ...,
}
In my case, roles was not. But it means that should be error 400 Bad Request.
The whole problem has nothing to do with shards configuration, etc. The error message was misleading.
Thanks to people in CouchDb slack channel for guiding me in the right direction.
How to collect the HTTP response status for a script?
Below is a sample code which will start a server and allow two routes for interaction.
using Genie
import Genie.Router: route
import Genie.Renderer.Json: json
Genie.config.run_as_server = true
route("/try/", method=GET) do
(:message => "Welcome") |> json
end
route("/test/", method=POST) do
data = jsonpayload()
<body>
end
Genie.startup()
How to collect the response status like 200, 500 or others as a string variable?
Open connection to your server using HTTP and look for the status field:
julia> using HTTP
julia> response = HTTP.get("http://127.0.0.1:8000/try")
HTTP.Messages.Response:
"""
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Genie/1.18.1/Julia/1.6.1
Transfer-Encoding: chunked
{"message":"Welcome"}"""
julia> response.status
200
If you rather want to control the status yourself you can add on the server side:
route("/tryerror/", method=GET) do
Genie.Responses.setstatus(503)
end
And now let us test it for 503:
julia> response = HTTP.get("http://127.0.0.1:8000/tryerror")
ERROR: HTTP.ExceptionRequest.StatusError(503, "GET", "/tryerror", HTTP.Messages.Response:
"""
HTTP/1.1 503 Service Unavailable
Content-Type:
Server: Genie/1.18.1/Julia/1.6.1
Transfer-Encoding: chunked
""")
For the last few weeks, we started getting CORS errors when trying to retrieve the auth token v2 API. We installed chrome CORS plugin and got that to work for now but then the flight fares API started giving CORS errors, we tried providing the regular cors headers in the request but to no avail. here is what is seen in the developer console. I am sending a GET request for the flight fares and tried the regular CORS headers as well but to no avail..
var getFlightFares = {
method: 'GET',
url: mainURL + "/v2/shop/flights/fares",
headers: {
'Authorization': 'Bearer '+token,
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': "/"
//'Access-Control-Allow-Origin': '*',
//'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
//'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
}
};
Result in developer console
GET
http://127.0.0.1:8080/spa/images/flights/sm%7B%7Bcheckout1.returnAirlineCode%7D%7D.gif [HTTP/1.1 200 OK 0ms]
OPTIONS
XHR
https://api.test.sabre.com/v2/auth/token [HTTP/1.1 200 OK 623ms]
POST
XHR
https://api.test.sabre.com/v2/auth/token [HTTP/1.1 200 OK 152ms]
Response :
Object { data: Object, status: 200, headers: dd/<(), config: Object, statusText: "OK" } sabre_integration.js:311:5
tokenT1RLAQJyP+PPcbBSEiIy9JBZrGkt4nu/dBD6CkzcyWI0njOM/Bbn3ngcAADA961ZaE1tN5y/bu57k0DseB5ocYDY9AIj64EwVJOr4RYAHKZF+H8tL7QnM35wjKYr40yjxkp1XL8lRDx84B+whxOMTaDreGnp1tDtFPhCGilvfeFpuXawbf1PjWAsR0uoNE9c0Pnmk8qWwuYEgNEkODYs8+K/peXF97LqylCFC6MWmkyodwSGwH7D/hjD5wTcSqJGLvARwo2NY/hplnArn8rY3sZ9gN3JV5PhqyPks56PYyD0Y5WvABg8YOVEA/Ud sabre_integration.js:312:5
OPTIONS
XHR
https://api.test.sabre.com/v2/shop/flights/fares [HTTP/1.1 404 Not Found 100ms]
Headers
Params
Response
departuredate2016-12-06destinationLAXlengthofstay5originJFKpointofsalecountryUS
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.test.sabre.com/v2/shop/flights/fares?origin=JFK&destination=LAX&departuredate=2016-12-06&lengthofstay=5&pointofsalecountry=US. (Reason: CORS preflight channel did not succeed). (unknown)
GET
http://127.0.0.1:8080/spa/images/flight_listing_sprite.png [HTTP/1.1 200 OK 33ms]
Try opening google chrome from command prompt with the commands:
"chrome.exe --disable-web-security --user-data-dir=/path/to/foo"
check there then
I'm trying to do a POST request using an access_token, and it works fine using POSTMAN, but when I try to do the same request on Delphi, I can't find a way to add the "Authorization=Bearer eyxxxxxx..." to the Request header, as POSTMAN does.
POSTMAN Request (working well):
POST /somepath HTTP/1.1
Host: someurl.com.br
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.....
Content-Type: application/json
(body content ommited)
Indy Request generated by Delphi, captured by HTTP Analyzer (always returning 401 Forbidden error, because the absence of "Authorization=Bearer" part):
POST /somepath HTTP/1.1
Host: someurl.com.br
Content-Type: application/json
(body content ommited)
I've tried to add the header using the code below, but the header part with the "Authorization=Bearer eyxxxxxx..." isn't generated on Request, returning the 401 Forbidden error.
FIdHTTP.Request.CustomHeaders.FoldLines := False;
FIdHTTP.Request.CustomHeaders.Add('Authorization=Bearer ' + txtToken.Text);
Just found the problem. I added the wrong separator between the "Authorization" and "Bearer" words.
Wrong:
FIdHTTP.Request.CustomHeaders.FoldLines := False;
FIdHTTP.Request.CustomHeaders.Add('Authorization=Bearer ' + txtToken.Text);
Correct:
FIdHTTP.Request.CustomHeaders.FoldLines := False;
FIdHTTP.Request.CustomHeaders.Add('Authorization:Bearer ' + txtToken.Text);
After replacing the '=' by ':', I received the expected response, like the one received by POSTMAN.
I'm trying to use the API on a website, here's the part of the manual:
Authenticated Sessions (taken from here)
To create an authenticated session, you need to request an authToken from the '/auth' API resource.
URL: http://stage.amee.com/auth (this is not my domain)
Method: POST
Request format: application/x-www-form-urlencoded
Response format: application/xml, application/json
Response code: 200 OK
Response body: Details of the authenticated user, including API
version.
Extra data: "authToken" cookie and header, containing the
authentication token that should be
used for subsequent calls.
Parameters: username / password
Example
Request
POST /auth HTTP/1.1
Accept: application/xml
Content-Type: application/x-www-form-urlencoded
username=my_username&password=my_password
Response
HTTP/1.1 200 OK
Set-Cookie: authToken=1KVARbypAjxLGViZ0Cg+UskZEHmqVkhx/Pm...;
authToken: 1KVARbypAjxLGViZ0Cg+UskZEHmqVkhx/PmEvzkPGp...==
Content-Type: application/xml; charset=UTF-8
QUESTION:
How do I get that to work?
I tried jQuery, but it seems to have problem with XSS. Actual code snippet would be greatly appreciated.
p.s.
All I was looking for was WebClient class in C#
You need to put application/json in your Accept header, this tells the server you want it to respond in that format - not xml.
I am using rails to extract the same authentication token cookie from stage.amee.com/auth as mentioned above. it took a bit of experimentation before I created and customised the correct request object that returned a 200 OK, with the authtoken as a cookie. i haven't found an effective method of reading the request object or I would post exactly what it looks like. here is my ruby code from the app's controller
#define parameters
uri=URI.parse('http://stage.amee.com')
#path = '/auth'
#login_details = 'username=your_username&password=your_password'
#headers = {'Content-Type' => 'application/x-www-form-urlencoded', 'Accept' => 'application/json'}
#create request object
req = Net::HTTP.new(uri.host, uri.port)
#send the request using post, defining the path, body and headers
resp, data = req.post(#path, #login_details, #headers)
#print response details to console
puts "response code = " << resp.code
puts "response inspect = " << resp.inspect
resp.each do |key, val|
puts "response header key : " + key + " = " + val
end
puts "data: " + data