ZRomik 2 Posted March 23, 2019 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
Angus Robertson 577 Posted March 23, 2019 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
Allen@Grijjy 44 Posted March 23, 2019 You spelled authorization wrong and it won't work otherwise. Share this post Link to post
ZRomik 2 Posted March 24, 2019 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
Angus Robertson 577 Posted March 24, 2019 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 1 Share this post Link to post
ZRomik 2 Posted March 24, 2019 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." 1 Share this post Link to post
Allen@Grijjy 44 Posted March 24, 2019 (edited) 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 March 24, 2019 by Allen@Grijjy Share this post Link to post
Angus Robertson 577 Posted March 25, 2019 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
ZRomik 2 Posted March 25, 2019 (edited) 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 March 25, 2019 by ZRomik Share this post Link to post
Angus Robertson 577 Posted March 25, 2019 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
ZRomik 2 Posted March 25, 2019 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
ZRomik 2 Posted March 26, 2019 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
Angus Robertson 577 Posted March 26, 2019 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
ZRomik 2 Posted March 26, 2019 (edited) 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 March 26, 2019 by ZRomik Share this post Link to post
Angus Robertson 577 Posted March 26, 2019 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
ZRomik 2 Posted March 26, 2019 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
Angus Robertson 577 Posted March 26, 2019 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
ZRomik 2 Posted March 26, 2019 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
ZRomik 2 Posted March 26, 2019 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
Angus Robertson 577 Posted March 26, 2019 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
ZRomik 2 Posted March 26, 2019 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
ZRomik 2 Posted March 26, 2019 autorefresh token not work if app in Idle, eg minimized to tray? Share this post Link to post
ZRomik 2 Posted March 27, 2019 (edited) 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 March 27, 2019 by ZRomik Share this post Link to post
Angus Robertson 577 Posted March 27, 2019 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
ZRomik 2 Posted March 28, 2019 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