Receiving 401 Unauthorized from http_get/3, but request works in browser

Hi all, my first post. Sorry for not using Markdown if it’s available, but I’m not sure it is working since I can’t find a preview panel.
I’ll follow the Help category format.
(EDIT: posting the message, I see that Markdown works and that it actually messed up some text; I’m reworking the message)

I’m using:

SWI-Prolog version 8.0.3

I want the code to:

A request to an external API works fine in the browser but it does not in SWI-Prolog (using http_get).
The request is against the API of a known application/service (Notion).
As per the official docs, the request only needs to include two headers for it to work:

  • “Authorization: Bearer (a certain key created in the app)
  • “Notion-Version: 2021-08-16”
    The request, if sent directly from the browser (I’m using a Chrome extension to modify the request’s headers), works. It returns some data from the application, which is a personal note-taking app.

But what I’m getting is:

In SWI-Prolog, the request returns a 401 Unauthorized error.
Now, such authorization errors are also given by the Notion API when the two headers are not set properly (but they are, since the test in the browser works).
Suspecting that the secure connection may be the problem here, I enabled debugging and I saw that the exception propagating the error comes ultimately from the ssl_negotiate/5 predicate.

My code looks like this:

test_get_database(Data) :-
  http_get('https://api.notion.com/v1/databases/61c2bb97a44740b782fc8fc40558c44a', Data, [
    request_header('Authorization', 'Bearer secret_9Tvk...............Nj03'),
    request_header('Notion-Version', '2021-08-16')
  ]).

This is the minimal testing code (I removed part of the key).

Enabling debug(http(_)) also yields this:

% [Thread pdt_console_client_0_Default Process] http_open: Connecting to 'api.notion.com':443 ...
% [Thread pdt_console_client_0_Default Process] 	ok <stream>(000001D6C54F9420) ---> <stream>(000001D6C54FAB80)
% [Thread pdt_console_client_0_Default Process] > GET /v1/databases/61c2bb97a44740b782fc8fc40558c44a HTTP/1.1
% [Thread pdt_console_client_0_Default Process] > Host: api.notion.com
% [Thread pdt_console_client_0_Default Process] > User-Agent: SWI-Prolog
% [Thread pdt_console_client_0_Default Process] > Connection: close
% [Thread pdt_console_client_0_Default Process] HTTP/1.1 401 Unauthorized
% [Thread pdt_console_client_0_Default Process] Date: Sun, 12 Sep 2021 20:35:48 GMT
% [Thread pdt_console_client_0_Default Process] Content-Type: application/json; charset=utf-8
% [Thread pdt_console_client_0_Default Process] Content-Length: 87
% [Thread pdt_console_client_0_Default Process] Connection: close
% [Thread pdt_console_client_0_Default Process] X-DNS-Prefetch-Control: off
% [Thread pdt_console_client_0_Default Process] X-Frame-Options: SAMEORIGIN
% [Thread pdt_console_client_0_Default Process] Strict-Transport-Security: max-age=5184000; includeSubDomains
% [Thread pdt_console_client_0_Default Process] X-Download-Options: noopen
% [Thread pdt_console_client_0_Default Process] X-Content-Type-Options: nosniff
% [Thread pdt_console_client_0_Default Process] X-XSS-Protection: 1; mode=block
% [Thread pdt_console_client_0_Default Process] Referrer-Policy: same-origin
% [Thread pdt_console_client_0_Default Process] Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' https://gist.github.com https://apis.google.com https://api.amplitude.com https://widget.intercom.io https://js.intercomcdn.com https://logs-01.loggly.com https://cdn.segment.com https://analytics.pgncs.notion.so https://o324374.ingest.sentry.io https://checkout.stripe.com https://js.stripe.com https://embed.typeform.com https://admin.typeform.com https://public.profitwell.com js.sentry-cdn.com https://js.chilipiper.com https://platform.twitter.com https://cdn.syndication.twimg.com https://www.googletagmanager.com https://x.clearbitjs.com https://client-registry.mutinycdn.com https://client.mutinycdn.com/ https://user-data.mutinycdn.com; connect-src 'self' https://msgstore.www.notion.so wss://msgstore.www.notion.so ws://localhost:* https://notion-emojis.s3-us-west-2.amazonaws.com https://s3-us-west-2.amazonaws.com https://s3.us-west-2.amazonaws.com https://notion-production-snapshots-2.s3.us-west-2.amazonaws.com https: http: https://api.amplitude.com https://api.embed.ly https://js.intercomcdn.com https://api-iam.intercom.io wss://nexus-websocket-a.intercom.io https://logs-01.loggly.com https://cdn.segment.com https://api.segment.io https://analytics.pgncs.notion.so https://api.pgncs.notion.so https://o324374.ingest.sentry.io https://checkout.stripe.com https://js.stripe.com https://cdn.contentful.com https://preview.contentful.com https://images.ctfassets.net https://www2.profitwell.com https://tracking.chilipiper.com https://api.chilipiper.com https://api.unsplash.com https://boards-api.greenhouse.io https://user-data.mutinycdn.com https://api-v2.mutinyhq.io https://api.statuspage.io https://pgncd.notion.so; font-src 'self' data: https://cdnjs.cloudflare.com https://js.intercomcdn.com; img-src 'self' data: blob: https: https://platform.twitter.com https://syndication.twitter.com https://pbs.twimg.com https://ton.twimg.com www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://github.githubassets.com https://js.chilipiper.com https://platform.twitter.com https://ton.twimg.com; frame-src https: http:; media-src https: http:
% [Thread pdt_console_client_0_Default Process] Set-Cookie: notion_browser_id=e68e8b73-6615-46f5-abc9-5a35c9653347; Domain=www.notion.so; Path=/; Expires=Wed, 21 May 2053 22:22:28 GMT; Secure
% [Thread pdt_console_client_0_Default Process] ETag: W/"57-QCRLT3IovYEW+CkwyJQlFtiXiG8"
% [Thread pdt_console_client_0_Default Process] Vary: Accept-Encoding
% [Thread pdt_console_client_0_Default Process] CF-Cache-Status: DYNAMIC
% [Thread pdt_console_client_0_Default Process] Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
% [Thread pdt_console_client_0_Default Process] Server: cloudflare
% [Thread pdt_console_client_0_Default Process] CF-RAY: 68dbec9cdbeffc89-FCO
...

Any clue as to why SSL would fail?
Also, other secure APIs seem to work (e.g. the one at https://jsonplaceholder.typicode.com/).
Unfortunately, my knowledge of SSL in general is very limited.
Thank you for any help.

Seems the SSL connection worked fine. The request headers are missing. This is due to wrong syntax. The docs say request_header(Name = Value) instead of using two arguments.

P.s. 8.0.3 is pretty old … If this is an old binary you are also many OpenSSL security fixes behind :frowning:

The request headers are missing. This is due to wrong syntax. The docs say request_header(Name = Value) instead of using two arguments.

That was the issue.

Thank you also for the suggestion to update the engine because of later fixes.