How can i read out Access-Token in response header

Hi

How can i read out an Access-Token in response header from a TWebHttpRequest?

Alternatively, how does TWebRESTClient work? This component isn't documented.

my login-call 

WebRESTClient1.HttpsPost('https://.../api/login/login','application/json','{"Password": "'+WebLoginPanel1.Password+'","Username": "'+WebLoginPanel1.User+'"}');

results in a

POST https://.../api/login/login 401 (Unauthorized)

index.html:1 Failed to load https://.../api/login/login: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 401.

But my RemObjectsSDK-HttpApi-Server delivers a Access-Control-Allow-Origin: * and TWebHttpRequest works fine also.

Thanks, Sven
  1. Are you sure the access token returns via a header? 
    Regardless, at this moment, the TWebHttpRequest returns only the HTTP request response data. We've added an extra event OnRequestResponse that will return the full request object so you will also be able to access the headers from this response object

    2) It is not clear why you would get a 401 from TWebRESTClient and not TWebHttpRequest as both internally use the same TJSXMLHttpRequest Javascript object. Maybe you can check with a (free) tool like Fiddler for differences in the HTTP requests between TWebRESTClient and TWebHttpRequest and perhaps differences in response?

Yes


WebHttpRequest1.Headers.AddPair('Content-Type','application/json');
WebHttpRequest1.Headers.AddPair('Accept','application/json');
WebHttpRequest1.URL := 'http://localhost:8099/api/login/login';
WebHttpRequest1.PostData := '{"Password": "test","Username": "test"}';
WebHttpRequest1.Execute;

POST http://localhost:8099/api/login/login HTTP/1.1
Host: localhost:8099
Connection: keep-alive
Content-Length: 39
Accept: application/json
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Content-Type: application/json
Referer: http://localhost:8000/TMSWeb_SimpleService/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7

{"Password": "test","Username": "test"}

HTTP/1.1 200 OK
Connection: close
Content-Type: application/json; charset=utf-8
Content-Length: 0
Date: Mon, 20 Aug 2018 05:23:16 GMT
Accept-Encoding: gzip, identity
Access-Control-Allow-Origin: *
Access-Token: {CA571BE7-0832-41CB-BD7E-D65FEF41618D}
Server: Remoting SDK


  WebRESTClient1.HttpsPost('http://localhost:8099/api/login/login','application/json','{"Password": "test","Username": "test"}');


POST http://localhost:8099/api/login/login HTTP/1.1
Host: localhost:8099
Connection: keep-alive
Content-Length: 39
Authorization: Bearer
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://localhost:8000/TMSWeb_SimpleService/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7

{"Password": "test","Username": "test"}

HTTP/1.1 401 Unauthorized
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Content-Length: 42
Date: Mon, 20 Aug 2018 05:25:50 GMT
WWW-Authenticate: Basic

Nicht unterstütztes Autorisierungs-Schema.


WebRESTClient1 sends
Authorization: Bearer
Accept: */*

How i can change Request Header in WebRESTClient?

You can use:

var
  headers: TCoreCloudHeaders;

begin
  AddHeader(headers, 'Authorization', 'Bearer ' + Token_Access);

  TWebRESTClient.HttpsPost(url, headers, data);
    
end;

This is not Authorisation problem. It has to do with the CORS capabilities of the server. See this and this for more


The problem is, as the message says, that the request does not include 'Access-Control-Allow-Origin=*' header. 
You can manually add it in the component but for some reason it doesn't go through. When I add it, Chrome does not recognise it although in the generated javascript the header is added.

Can someone at TMS check this please?

As a proof that there is something wrong with the pass of the headers, you can download this Chrome extension:
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en

and run the request with the extension enabled/disabled.

What it basically does is to intercept the http request and add the same header. Basically, what we are trying to achieve manually.

Should I build an example with RemObjectsSDK Server?

I uploaded an example to GitHub.


https://github.com/landrix/RemObjectsSDK-Samples/tree/master/REST-TMSWebCore

You can start the RemObjectsSDK server with _startServer.bat or compile the exe for your own.

Then try to login with TMS-Client. Debugger in Chrome shows me

POST http://localhost:8099/api/login/login 401 (Unauthorized)
ClientTMSWebCore.html:1
Failed to load http://localhost:8099/api/login/login: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 401.

Swagger and Curl works fine

curl -v -X POST "http://localhost:8099/api/login/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"Password\": \"test\", \"Username\": \"test\"}"
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8099 (#0)
> POST /api/login/login HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:8099
> accept: application/json
> Content-Type: application/json
> Content-Length: 41
>
* upload completely sent off: 41 out of 41 bytes
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 0
< Date: Thu, 30 Aug 2018 13:52:36 GMT
< Accept-Encoding: gzip, identity
< Access-Control-Allow-Origin: *
< Access-Token: {E1864BD2-B4F4-4B09-B641-96375702BD7F}

can you check this please? Thanks

Can you give any hints on this please?


Which property i need to read out in ARequest: TJSXMLHttpRequest to become full response content?

I can not continue working. Thanks

I'm not an expert in the remobjects sdk but looking at the error , it looks like CORS is not enabled for this server.
Please see: https://talk.remobjects.com/t/roserver-how-to-add-cors-support/6620 

Same topic is also here:

https://talk.remobjects.com/t/cross-origin-javascript-client/9924/4

It seems from there you need to set TROIndyHTTPServer.SendCrossOriginHeader  to true 
yes, i know,  TROIndyHTTPServer.SendCrossOriginHeader is set to true

see at github

https://github.com/landrix/RemObjectsSDK-Samples/blob/master/REST-TMSWebCore/ServerUnit1.pas#L76

and see also curl response

but WebCore don't work

Still the error you gave us says:


Failed to load http://localhost:8099/api/login/login: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 401.

so, this does mean that CORS is not enabled. Maybe there is something more you need to do with the remobjects server. I'm not an expert in the remobjects sdk. If the problem persists, perhaps you can contact remobjects.

OK, I will check that. Thanks.

Can you say anything about my second question above?

Which property i need to read out in ARequest: TJSXMLHttpRequest to become full response content?

after adding Access-Token to the Access-Control-Expose-Headers
at RemObjectsSDK Server, i can now read out the token on client-side

here the crosspost

https://talk.remobjects.com/t/is-set-a-custom-access-control-expose-headers-needed/17372



but one more note to TMS WebCore

is it right to set the Authorization Bearer if FAccessToken is an empty string?

i think 

procedure TRESTClient.HttpsPut(URL, ContentType, Data: string);
and
procedure TRESTClient.HttpsPost(URL, ContentType, Data: string);

should check on emtpy FAccessToken

  if FAccessToken <> '' then
    FReq.setRequestHeader('Authorization', 'Bearer ' + FAccessToken);

i think the other FReq.setRequestHeader('Authorization', 'Bearer ' + FAccessToken); should check this also to.
I have tested only POST-methods.

This is indeed a good improvement and helps for working with endpoints that do not require the access token. We've applied this improvement and it will be included in the next update.