Jump to content

Recommended Posts

Hello all!

I'm writing small program for  rest authorization. So, authorization process is OK. I successfull get "access" and "refresh" tokens. Next I need to post GET request on some url with the following header: "Authorization: Bearer *Access token wich I got*"

In the internet I fouded an example how to write get request and writed following code:

procedure TForm1.RetrieveUserInfo;
var
  url: string;
  rcv: TMemoryStream;
begin
  url := sAuthURL + 'oauth/verify';
  rcv := TMemoryStream.Create;
  slhtpcli.RcvdStream := rcv;
  slhtpcli.ExtraHeaders.Add('Autorization: Bearer ' + FAccToken);
  mmo1.Lines.Clear;
  slhtpcli.URL  := url;
  try
    slhtpcli.GetASync;
  finally
    mmo1.Lines.LoadFromStream(rcv);
    FreeAndNil(rcv);
  end;
end;

Response from server always empty. What I'm writed wrong?

Share this post


Link to post

I added a new component TSslHttpRest in V8.58 which makes several of your lines redundant, look at the new sample project OverbyteIcsHttpRestTst which also illustrates OAuth2.

 

Also,  TSslHttpCli has a new property THttpAuthType that adds httpAuthBearer and httpAuthToken, and AuthBearerToken for OAuth so you don't need to use ExtraHeaders.

 

Angus

 

Share this post


Link to post
13 hours ago, Angus Robertson said:

I added a new component TSslHttpRest in V8.58 which makes several of your lines redundant, look at the new sample project OverbyteIcsHttpRestTst which also illustrates OAuth2.

 

Also,  TSslHttpCli has a new property THttpAuthType that adds httpAuthBearer and httpAuthToken, and AuthBearerToken for OAuth so you don't need to use ExtraHeaders.

 

Angus

 

As I telling yesterday the authorization process is OK. I'm using TRestOAuth component  and got "access" and "refresh" tokens. Next I must post GET request as I described and get an response in JSON format similar to the following:

Quote

{
    "CharacterID": 273042051,
    "CharacterName": "CCP illurkall",
    "ExpiresOn": "2014-05-23T15:01:15.182864Z",
    "Scopes": " ",
    "TokenType": "Character",
    "CharacterOwnerHash": "XM4D...FoY="
}

In docs for EVE SSO describes how to Obtaining Character ID:

Quote

Once you have obtained an access token, you can ask the login server for some details of the character that was used to authenticate.

This step is entirely optional, as all you need to authenticate to ESI is the access token.

To get the character ID from the SSO server make an HTTP GET request to https://esi.tech.ccp.is/verify/ that looks like this:


GET https://esi.tech.ccp.is/verify/

User-Agent: ...
Authorization: Bearer uNEEh...a_WpiaA2
Host: esi.tech.ccp.is

Important parameters are:

Authorization header - “Bearer” plus the access token from step 2 A successful request will yield a response in JSON format similar to the following:


{
    "CharacterID": 273042051,
    "CharacterName": "CCP illurkall",
    "ExpiresOn": "2014-05-23T15:01:15.182864Z",
    "Scopes": " ",
    "TokenType": "Character",
    "CharacterOwnerHash": "XM4D...FoY="
}

When I trying to post GET request with described parameters the response from server is always empty. I.e. rcv.Size = 0. I trying set URL property of TSSlHttpCli component to "http://www.google.com" but response from server is empty. I think what I'm doing something wrong.

Share this post


Link to post

As Allen said, you spelled Authorization wrong, one reason to use the new property rather than write your own headers. 

 

Also you are using async methods but not waiting for a response, you should use sync methods if you want a simple application.

 

Exactly what header responses do you get with the correct spelling. 

 

Angus


 
  • Like 1

Share this post


Link to post
8 hours ago, Angus Robertson said:

As Allen said, you spelled Authorization wrong, one reason to use the new property rather than write your own headers. 

 

Also you are using async methods but not waiting for a response, you should use sync methods if you want a simple application.

 

Exactly what header responses do you get with the correct spelling. 

 

Angus



 

I'm trying to run the OverbyteIcsHttpRestTst  demo app.  When I press "Start REST Request" button  I see in log that message: "HTTP Error 400. The request has an invalid header name."

  • Confused 1

Share this post


Link to post
4 hours ago, ZRomik said:

HTTP Error 400. The request has an invalid header name.

I think an incorrectly spelled name like autorization would qualify as an invalid header name.  Also, just because you have an access token or refresh token, doesn't mean you made a request using an authorization header yet, as those required for bearer tokens.  It is very common to use query parameters as part of a URI path to obtain the access and refresh token on OAuth implementations.

Edited by Allen@Grijjy

Share this post


Link to post
15 hours ago, ZRomik said:

I'm trying to run the OverbyteIcsHttpRestTst  demo app.  When I press "Start REST Request" button  I see in log that message: "HTTP Error 400. The request has an invalid header name."

The sample logs all the request and response headers, we need to see those to explain why you get a 400 error.

 

Angus

 

Share this post


Link to post
1 hour ago, Angus Robertson said:

The sample logs all the request and response headers, we need to see those to explain why you get a 400 error.

 

Angus

 

Where I can find log-file? And how I can wait response from server?

Edited by ZRomik

Share this post


Link to post
1 hour ago, ZRomik said:

Where I can find log-file? And how I can wait response from server?

On the REST sample Settings tab, you select Debug Logging as 'HTTP Header' or 'HTML Body', and the headers appear in the log window.  The latest version in V8.60 adds a Log Directory field which also write the window to a disk log file, if specified. 

 

Angus

Share this post


Link to post

I'm not understood what's happened... I'm changed auth url from "/oauth/v2/" to simply "/oauth/" and all working fine now. Maybe,  this is errors on server side realisation of oauth2 protocol?
Anyway, Angus and Allen, big thanks for useful help! 

Share this post


Link to post

Angus, how important these lines in demo app: 

    HttpRest1.DebugLevel := THttpDebugLevel(DebugLogging.ItemIndex);
    HttpRest1.CertVerMethod := TCertVerMethod(CertVerMethod.ItemIndex);
    HttpRest1.SslCliSecurity := TSslCliSecurity(SslSecurity.ItemIndex);
    HttpRest1.SslReportChain := ReportCertChain.Checked;
    HttpRest1.SslRootFile := SslRootBundleFile.Text;
    HttpRest1.ServerAuth := THttpAuthType(AuthType.ItemIndex);
    HttpRest1.Username := AuthLogin.Text;
    HttpRest1.Password := AuthPassword.Text;
    HttpRest1.AuthBearerToken := AuthBearer.Text;
    HttpRest1.ExtraHeaders := ExtraHeaders.Lines;
    HttpRest1.SocketFamily := sfAny;  { V8.57 IP4 and IPV6 }

I trying get user info in my own app but got empty response from server.

Share this post


Link to post

Most of those values you will set according to the requirements of your application, they are self explanatory from the fields on the sample application, but you won't need username and password with OAuith2. 

 

As requested previously, if you expect help debugging your application, you need to post the request and response headers ICS sent and received, not just tell us it did not work.

 

Angus

 

Share this post


Link to post

Headers from ICS:

Quote

GET https://login.eveonline.com/oauth/verify
Connected to: login.eveonline.com
> GET /oauth/verify HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0
> Host: login.eveonline.com
> Authorization: Bearer AGkOYA18eMqlMdnUCPZp96_cVFg2d2v6pm64Ekvr1qVaMuimMWg_ep2hLC5-yXNlhO2xhyPX_c3vOGfI_K-o9Q

login.eveonline.com SSL Connected OK with TLSv1.2, cipher ECDHE-RSA-AES128-GCM-SHA256, key auth RSA, key exchange ECDH, encryption AESGCM(128), message auth AEAD
< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/8.5
< Content-Security-Policy: default-src 'self'; img-src 'self' data: *.facebook.com image.eveonline.com web.ccpgamescdn.com; font-src 'self' web.ccpgamescdn.com fonts.gstatic.com; style-src 'self' 'unsafe-inline' web.ccpgamescdn.com hello.myfonts.net; script-src 'self' 'nonce-4rGbfbJ6zEee5mGr5qiYmQ==' connect.facebook.net az416426.vo.msecnd.net; connect-src dc.services.visualstudio.com; frame-ancestors launcher.testeveonline.com launcher.eveonline.com; frame-src connect.facebook.net www.facebook.com; report-uri https://ccpgames.report-uri.com/r/t/csp/enforce
< Report-To: {'group':'default','max_age':31536000,'endpoints':[{'url':'https://ccpgames.report-uri.com/a/t/g'}],'include_subdomains':true}
< NEL: {'report_to':'default','max_age':31536000,'include_subdomains':true}'
< Date: Tue, 26 Mar 2019 09:57:23 GMT
< Content-Length: 236
Request done. Request code #0
 

In demo-app I can retrieve user info from server, but can't do it from my own app.

 

Headers from demo app:

Quote

GET https://login.eveonline.com/oauth/verify
Connected to: login.eveonline.com
> GET /oauth/verify HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0
> Host: login.eveonline.com
> Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkpXVC1TaWduYXR1cmUtS2V5IiwidHlwIjoiSldUIn0.eyJzY3AiOiJlc2ktbG9jYXRpb24ucmVhZF9sb2NhdGlvbi52MSIsImp0aSI6IjI5YzQzMGZiLWE3ZTQtNGEyNS04Y2NjLWRmZGE1MjNhNjJmYSIsImtpZCI6IkpXVC1TaWduYXR1cmUtS2V5Iiwic3ViIjoiQ0hBUkFDVEVSOkVWRTo5MTk3NDk3MiIsImF6cCI6ImM2NDdhYjRmZGNlYTQ0ZmZhYWE4YTIzOTU3OTdhNmVmIiwibmFtZSI6IlJhemllbCBTb3RrZW4iLCJvd25lciI6IkFBZFVoR0ZIWm1UcS9JRVphdjVXSko2eGx5az0iLCJleHAiOjE1NTM1OTU3MzYsImlzcyI6ImxvZ2luLmV2ZW9ubGluZS5jb20ifQ.IBOBg3YvemyEcTxc85Js82DaOj2OMCztY6jm5z9UL-3V2qh6QDZONj4Ehg3hIVSfMHK0Wh6wP8lpjsnh9OVFnlAJ-Q3s5qwKPqR7vKq-6yH-v3SNmwR4zDLd8TmkU2jVup0As--UiFomVgn7MBYzvjCqndj8ysmPwABIvBaEr1DpyvyhJS8Hks7DIrgMeVad3dmct7_5ZutGvjZtf7AOUhxiKyrrd43_hOMivAVwoPXnJSAxK4z0gyKfvJFp9_fv4G_5DzGLeZwvXclata8ZZz_3a8jwKd-bJfBsxOMzq81XHZ-9eSbwazCVhNndG6QCqmaAwDXAcmHWVS5Ll6Q7dg

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/8.5
< Content-Security-Policy: default-src 'self'; img-src 'self' data: *.facebook.com image.eveonline.com web.ccpgamescdn.com; font-src 'self' web.ccpgamescdn.com fonts.gstatic.com; style-src 'self' 'unsafe-inline' web.ccpgamescdn.com hello.myfonts.net; script-src 'self' 'nonce-ZMht8ljZEUmtN1c0+CFp3w==' connect.facebook.net az416426.vo.msecnd.net; connect-src dc.services.visualstudio.com; frame-ancestors launcher.testeveonline.com launcher.eveonline.com; frame-src connect.facebook.net www.facebook.com; report-uri https://ccpgames.report-uri.com/r/t/csp/enforce
< Report-To: {'group':'default','max_age':31536000,'endpoints':[{'url':'https://ccpgames.report-uri.com/a/t/g'}],'include_subdomains':true}
< NEL: {'report_to':'default','max_age':31536000,'include_subdomains':true}'
< Date: Tue, 26 Mar 2019 10:03:11 GMT
< Content-Length: 236
Request completed: 200 OK
Request done, StatusCode #200
{"CharacterID":91974972,"CharacterName":"Raziel Sotken","ExpiresOn":"2019-03-26T10:22:16","Scopes":"esi-location.read_location.v1","TokenType":"Character","CharacterOwnerHash":"AAdUhGFHZmTq/IEZav5WJJ6xlyk=","IntellectualProperty":"EVE"}
Json main content type: stObject
Sync request completed, Status 200
 

 

Edited by ZRomik

Share this post


Link to post

Both requests seem to work, they both return 200 success and the same length content, so it would appear you are not correctly reading the JSON data returned by the server. 

 

The Authorization header is different in the two requests, despite both requests seemingly being successful.

 

Angus

 

Share this post


Link to post

In demo app I seen:

Quote

    if ((Pos('{', HttpRest1.ResponseRaw) > 0) or
           (Pos('[', HttpRest1.ResponseRaw) > 0)) and
                Assigned(HttpRest1.ResponseJson) then begin
 

In my own app the "ResponseJson" property always equal empty string. 

Share this post


Link to post

What is in ResponseRaw?  Should be 236 bytes of data per the demo.  If not, your code is different to the demo.

 

Angus

 

Share this post


Link to post

In this procedure I trying  to retrieve user info:

procedure TForm1.RetrieveUserInfo(const AToken: string);
var
  url: string;
  code: Integer;
begin
  slhtprest.AuthBearerToken   := AToken;
  slhtprest.ServerAuth        := httpAuthBearer;
  slhtprest.DebugLevel        := DebugHdr;
  url                         := sAuthURL + sVerifyPath;
  slhtprest.SocketFamily      := sfAny;
  slhtprest.RestRequest(httpGET, url, True, '');
end;

 

Share this post


Link to post

While testing apps got different responses

In demo app:

Quote

GET https://login.eveonline.com/oauth/verify
Connected to: login.eveonline.com
> GET /oauth/verify HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0
> Host: login.eveonline.com
> Authorization: Bearer 5bfWVHDGx1DqDmQQr8Da0RcNNQ-jZguUFmSNG4_SDsX8JB74Rg5CnVlKyrAUjjYuSuIcIMns2scfSDZjFq43-w

< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/8.5
< Content-Security-Policy: default-src 'self'; img-src 'self' data: *.facebook.com image.eveonline.com web.ccpgamescdn.com; font-src 'self' web.ccpgamescdn.com fonts.gstatic.com; style-src 'self' 'unsafe-inline' web.ccpgamescdn.com hello.myfonts.net; script-src 'self' 'nonce-pi0YBI2RyEy4JPW3PL5dlg==' connect.facebook.net az416426.vo.msecnd.net; connect-src dc.services.visualstudio.com; frame-ancestors launcher.testeveonline.com launcher.eveonline.com; frame-src connect.facebook.net www.facebook.com; report-uri https://ccpgames.report-uri.com/r/t/csp/enforce
< Report-To: {'group':'default','max_age':31536000,'endpoints':[{'url':'https://ccpgames.report-uri.com/a/t/g'}],'include_subdomains':true}
< NEL: {'report_to':'default','max_age':31536000,'include_subdomains':true}'
< Date: Tue, 26 Mar 2019 15:23:15 GMT
< Content-Length: 245
Request completed: 200 OK
Request done, StatusCode #200
{"CharacterID":95187382,"CharacterName":"Albert Sokolov","ExpiresOn":"2019-03-26T15:42:25.9450361","Scopes":"esi-location.read_location.v1","TokenType":"Character","CharacterOwnerHash":"htV2nwYcjz/+ChdoWd8zOqKKUmI=","IntellectualProperty":"EVE"}
Json main content type: stObject
Sync request completed, Status 200
 

In my own app:

Quote

GET https://login.eveonline.com/oauth/verify
Connected to: login.eveonline.com
> GET /oauth/verify HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0
> Host: login.eveonline.com
> Authorization: Bearer zTCdLjbYD6wiXxEDeQfhYY6kAxcMgKbazGZ1xrq_M4YkAw430fd-pSXcfLE7avAr8l3Plj8_DBW6O_BNPmJmBA

login.eveonline.com SSL Connected OK with TLSv1.2, cipher ECDHE-RSA-AES128-GCM-SHA256, key auth RSA, key exchange ECDH, encryption AESGCM(128), message auth AEAD
< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/8.5
< Content-Security-Policy: default-src 'self'; img-src 'self' data: *.facebook.com image.eveonline.com web.ccpgamescdn.com; font-src 'self' web.ccpgamescdn.com fonts.gstatic.com; style-src 'self' 'unsafe-inline' web.ccpgamescdn.com hello.myfonts.net; script-src 'self' 'nonce-m6Uc+FMwy0CLk8wPHi/q/g==' connect.facebook.net az416426.vo.msecnd.net; connect-src dc.services.visualstudio.com; frame-ancestors launcher.testeveonline.com launcher.eveonline.com; frame-src connect.facebook.net www.facebook.com; report-uri https://ccpgames.report-uri.com/r/t/csp/enforce
< Report-To: {'group':'default','max_age':31536000,'endpoints':[{'url':'https://ccpgames.report-uri.com/a/t/g'}],'include_subdomains':true}
< NEL: {'report_to':'default','max_age':31536000,'include_subdomains':true}'
< Date: Tue, 26 Mar 2019 15:22:02 GMT
< Content-Length: 237
Request done. Request status #200
 

Responses has different size and different content. But ResponseRaw in my app is stll empty.

Share this post


Link to post
slhtprest.RestRequest(httpGET, url, True, '');

The third parameter is 'AsyncReq: Boolean = False;' which you have set true so you making asynchronous requests still, as per your root message,  But it is not clear from anything you posted whether you are waiting for a response to your requests, or assuming the content is available immediately the request starts and that function returns. 

 

Either change that parameter to false to make it a synchronous request which means it won't return until there is a response, or process the response in the OnRestRequestDone event as the demo application does.

 

Angus

Share this post


Link to post

Change  AsyncReq to false, but nothing changes:

Quote

GET https://login.eveonline.com/oauth/verify
Connected to: login.eveonline.com
> GET /oauth/verify HTTP/1.1
> Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*, application/json
> Accept-Encoding: gzip, deflate
> User-Agent: Mozilla/4.0
> Host: login.eveonline.com
> Authorization: Bearer 1hTMybOl3_PRZPBvLtqj5RYOh7iy2PUqiusP5BCCaEnnLKiTTVwpcZkZBGgvIrNtAlx9jEWUB7wC2NPpNpMbSg

login.eveonline.com SSL Connected OK with TLSv1.2, cipher ECDHE-RSA-AES128-GCM-SHA256, key auth RSA, key exchange ECDH, encryption AESGCM(128), message auth AEAD
< HTTP/1.1 200 OK
< Cache-Control: private
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/8.5
< Content-Security-Policy: default-src 'self'; img-src 'self' data: *.facebook.com image.eveonline.com web.ccpgamescdn.com; font-src 'self' web.ccpgamescdn.com fonts.gstatic.com; style-src 'self' 'unsafe-inline' web.ccpgamescdn.com hello.myfonts.net; script-src 'self' 'nonce-yAfG0RJxbESZgzZKORotEA==' connect.facebook.net az416426.vo.msecnd.net; connect-src dc.services.visualstudio.com; frame-ancestors launcher.testeveonline.com launcher.eveonline.com; frame-src connect.facebook.net www.facebook.com; report-uri https://ccpgames.report-uri.com/r/t/csp/enforce
< Report-To: {'group':'default','max_age':31536000,'endpoints':[{'url':'https://ccpgames.report-uri.com/a/t/g'}],'include_subdomains':true}
< NEL: {'report_to':'default','max_age':31536000,'include_subdomains':true}'
< Date: Tue, 26 Mar 2019 16:41:24 GMT
< Content-Length: 237
Request done. Request status #200
 

I'm handle OnRequestDone event:

procedure TForm1.slhtprestRequestDone(Sender: TObject; RqType: THttpRequest;
  ErrCode: Word);
var
  json: tjsonobject;
begin
  if ErrCode <> 0 then
    mmo1.Lines.Add('Error while retrieving user data. Error #' + IntToStr(ErrCode))
else
  mmo1.Lines.Add('Request done. Request status #' + IntToStr(slhtprest.StatusCode));
  if slhtprest.ResponseRaw <> '' then
  begin
    if Pos('{', slhtprest.ResponseRaw) > 0 then
    begin
	 here be work with json object from response
    end;
  end;
end;

 

Share this post


Link to post

Angus, I set a breakpoint on line 1448 in file OverbyteIcsSslHttpRest.pas. So, the event OnRestRequestDone raise only when app get access token. The raw response is:

Quote

'{"access_token":"swp_hDAjWicjPuDKKpPtE6ewMCyEc_QUEI3ZwsJDdrOdPSskj-uFItmpv2hFbxuM4EFq_aS-jHBuvCqYBw3p3A","token_type":"Bearer","expires_in":1199,"refresh_token":"x3QBi7JqJ3KgQYURlzfNESS6dVVcx6LtDBkxe0k8u5g"}'

When I manual doing request then event not raising and FResponseRaw field not set value. In demo app these event raise both times. When I get tokens an when I doing manual rest request

Edited by ZRomik

Share this post


Link to post

Sorry, but if the component works correctly in the ICS sample application returning the correct information, there is no reason why it should not work in your own application, provided all the correct parameters are passed and you use the same events.  

 

Angus

Share this post


Link to post

Angus, this event raise one time inside component TSslHttpRest.

I.e. procedure onHttpRequestDone calling only first time, when process authorization request. When I call procedure RestRequest this event does'nt raise. I can't understood why this strange thing  happens.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×