HTTPApi Authentication in Delphi

Hi,

I’ve been experimenting with HTTPApi in Delphi and have a basic handle on it.

However I’m trying and failing to understand authentication.
I’ve found the sample application but I can’t understand how it works.
I’ve tried calling the login/login endpoint from Postman with a blank Access-Token header but the TROHttpApiSession.Create(’’, EmptyGUID) call fails.

Could you let me know where I’m going wrong or is there any documentation on HTTPApi authentication in general?

Thanks

Hi,

when you call login method - it returns Access-Token: {3099F79B-4550-47F4-883E-82B8B275243F} in response headers.

see example of execution of methods via CURL at ServiceRequiresLogin in Delphi - #10 by EvgenyK
Note: Pay attention that verbose mode (-v) is required

later you should provide received guid in request header for accessing to protected service’s methods.

Note: You should use TROHttpApiSimpleAuthenticationManager otherwise Access-Token in headers won’t be work as expected.
see HttpApi Authentication sample for more details.

Thanks.

Sorry but I’m an old-school Win32 developer and am a bit of a noob when it comes to this REST stuff. I’ve just been asked to investigate providing an API to some server functions.

I’ve tried the sample app and imported the swagger API from http://localhost:8099/api into Postman and then using that to test.

When I call the login/login function/endpoint, I seem to get five headers back in the response but none of them are Access-Token or contain a GUID.

I’m clearly doing something wrong here I just can’t work out exactly what :slight_smile:

Specifically, it seems this call:

result := TROHttpApiSession.Create(’’, EmptyGUID);

Is returning an empty GUID. Should this be happening and is that the root problem?
(I’m guessing here)

Sorry, me again.

I’ve just tried the curl example from the thread you linked (when I was last trying this a couple of years ago) and I get this:

Note: Unnecessary use of -X or --request, POST is already inferred.

  • Trying 127.0.0.1:8099…
  • Connected to localhost (127.0.0.1) port 8099 (#0)

POST /api/login/login HTTP/1.1
Host: localhost:8099
User-Agent: curl/7.79.1
Referer: rbose
accept: application/json
content-type: application/json
Content-Length: 38

  • Mark bundle as not supporting multiuse
    < HTTP/1.1 500 OK
    < Connection: close
    < Content-Type: text/html; charset=utf-8
    < Content-Length: 34
    < Date: Tue, 01 Feb 2022 12:51:35 GMT
    < Accept-Encoding: gzip, identity
    <
    Invalid Path* Closing connection 0

Which looks like the example in that thread except Access-Token is missing for some reason.

I’m going to compare with the example app in that other thread I think as I obviously managed to get that to work back in 2020 and I’ve just forgotten it all since then.

UPDATE: Yep the httpapi_security.zip from the other thread does the same thing. It actually throws an exception when I call the login endpoint:

‘This stream is incompatible with JSON format. Position: 6’

It looks like I got this working before so not sure if I’m doing something different.

Hi,

this is correct code. at this step you haven’t any valid session id because request header doesn’t contain it.


My steps:

  • Launch the the HttpApi Authentication sample.

  • open in browser http://localhost:8099/api and copy raw data

  • open Swagger Editor and paste that data. you will have
    Untitled
    Note: only /login/login methods doesn’t require authorization.

  • launch this method:

C:\>curl -v -X POST "http://localhost:8099/api/login/login" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"NewParam\": \"1\",  \"NewParam1\": \"1\"}"
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8099 (#0)
> POST /api/login/login HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.56.0
> accept: application/json
> content-type: application/json
> Content-Length: 38
>
* upload completely sent off: 38 out of 38 bytes
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 0
< Date: Tue, 01 Feb 2022 13:00:09 GMT
< Accept-Encoding: gzip, identity
< Access-Token: {3A193630-B199-4EDD-8ED0-64EA12F6737D}
<
* Closing connection 0

as you can see, server returns Access-Token: {3A193630-B199-4EDD-8ED0-64EA12F6737D}

  • launch another method like getdate or Sum and include that Access-Token:
C:\>curl -v -X POST "http://localhost:8099/api/test/getdate" -H  "accept: application/json" -H  "Access-Token: {3A193630-B199-4EDD-8ED0-64EA12F6737D}"
*   Trying ::1...
* TCP_NODELAY set
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8099 (#0)
> POST /api/test/getdate HTTP/1.1
> Host: localhost:8099
> User-Agent: curl/7.56.0
> accept: application/json
> Access-Token: {3A193630-B199-4EDD-8ED0-64EA12F6737D}
>
< HTTP/1.1 200 OK
< Connection: close
< Content-Type: application/json; charset=utf-8
< Content-Length: 26
< Date: Tue, 01 Feb 2022 13:02:04 GMT
< Accept-Encoding: gzip, identity
< Access-Token: {3A193630-B199-4EDD-8ED0-64EA12F6737D}
<
"2022-02-01T13:02:04.086Z"* Closing connection 0

Thanks.

Ok the exception was because I hadn’t properly escaped the double-quotation marks in the body text.
Doing so now works correctly via curl at the command line with both examples so I’m getting somewhere.

Now I just need to figure out why Postman isn’t returning the Access-Token header correctly but that looks like it might be a Postman-specific issue.

And now Postman is working too so don’t know what the issue was there but all looking good now.

Thanks for the help :slight_smile:

Hi,

Swagger Editor created correct CURL string for me when I pressed Try it out

When I try the Swagger Editor, it’s trying to use the endpoint URL https://editor.swagger.io/api/login/login

Not sure how I tell it to use http://localhost:8099/api/

Hi,

I add it manually because I haven’t valid endpoint URL at all

curl -X POST "/login/login" -H  "accept: application/json" -H  "content-type: application/json" -d "{  \"NewParam\": \"1\",  \"NewParam1\": \"1\"}"

Yeah I just realised I was being an idiot

Slightly separate question but I’ll keep it in here.

I’m trying to get SSL working on the server and I always have problems with SSL.

Currently I’m using the TROHttpServer. I can set OpenSSL.SSLEnabled to True without a problem and then access it at https://localhost:8099/api but have to bypass the security warnings.

I want to use a local self-signed certificate so I don’t get the warnings and can test clients properly but can’t figure out how.

What files/properties do I need to add my own cert to the TROHttpServer.
I don’t actually care which server I use so if it’s easier with the Indy server instead I could use that.

Hi,

Check these properties of TROHttpServer.OpenSSL:

    /// <summary>default CA certificate file </summary>
    property CAFile: string read fCAFile write fCAFile;
    /// <summary>default locations for trusted CA certificates</summary>
    property CADir: string read fCADir write fCADir;
    /// <summary>
    /// certificate file that contains cert.pem + key.pem [+ CAcert.pem ] [+ rootcert.pem]
    /// </summary>
    property CertFile: string read fCertFile write fCertFile;

In Indy you should specify similar options of TIdServerIOHandlerSSLOpenSSL.SSLOptions:

    property RootCertFile: String read fsRootCertFile write fsRootCertFile;
    property CertFile: String read fsCertFile write fsCertFile;
    property KeyFile: String read fsKeyFile write fsKeyFile;

Thanks, I’m just not clear on which particular files I need in which properties. PFX/CRT/PEM/etc etc

Also are these properties paths to the relevant files or the content of the files themselves pasted in?

Hi,

it’s a filenames like

  IdServerIOHandlerSSLOpenSSL1.SSLOptions.RootCertFile := 'rootcert.pem';
  IdServerIOHandlerSSLOpenSSL1.SSLOptions.CertFile := 'server.pem';
  IdServerIOHandlerSSLOpenSSL1.SSLOptions.KeyFile := 'server.pem';

Thanks I got it working :slight_smile: