HTTPSocket HTTPS Basic Auth

Hi,

I’m trying to implement REST API calls to MailJet using Xojo.Net.HTTPSocket, Mailjet requires HTTPS Basic Auth.

All Email API endpoints requests are authenticated using HTTPS Basic Auth. It requires you to provide a username and a password for each API request.

Doc here

Using Xojo 2019r3.1

The PageReceived event always returns 401

I tried using the AuthenticationRequired event:

System.DebugLog("Auth required")
Name = "myusername"
Password = "mypassword"
Return True

It seems that AuthenticationRequired is not fired.

I tried passing directly the Basic Authentication using the request Header

http.RequestHeader("Authorization") = "Basic " + auth // where auth is an Base64 encoded "myusername:mypassword"

Same 401 error.

I tried both in simulator and on a physical device.

I tried with Postman app, and it works with the same user:password.

Does someone uses Xojo.Net.HTTPSocket with Basic Auth successfully ?

Is it an Xojo bug, an iOS limitation ?

Thanks !

What are you using to Base64 encode ?
Did you compare the Base64 encode of “user:password” in iOS versus the same produced in a desktop app?

EDIT: you can actually compare the Base64 encode to the one produced in Postman > Headers > Authorization

EDIT2: I believe AuthenticationRequired event is only used when there are .htaccess / .htpasswd files that request username and password to access the ressource.

I’m encoding with M_Text extensions module from M. Bujardet.
Using it in multiple apps with success.

But passing user/password should work…
What’s strange is the event not being fired.

AuthenticationRequired event will not fire when Basic Auth request header is used. Those are two completely different Auth methods.

I’ll try with HeaderRequest in postman using my base64 string.
I’ll post the results.
Thanks.

Note that Xojo doc says about AuthenticationRequired

 Called when the connection requires HTTP basic authentication. Set the name and password and return True.

Here are my findings …

I’m not sure about that…
Testing with Postman app, when you select Authorization ‘Basic Auth’ it creates automatically a Header with Authorization: Basic Base64

Yes, I created a macOS test app, using the same module and replacing the M_Text base64 encoding by Xojo EncodeBase64.
Both generated strings are identical.
The macOS http.Send returns the same HTTP 401.

This is what I did. Both are identical.
I tried copying the Postman string ‘Basic XXXX…’ and using the string directly in the app (no Base64 conversion), it doesn’t work either.

I tried using exactly the Postman Headers

http.RequestHeader("Content-Type") = "application/json"
http.RequestHeader("Authorization") = "Basic XXXX"
http.RequestHeader("Cache-Control") = "no-cache"
http.RequestHeader("Accept") = "*/*"
http.RequestHeader("Accept-Encoding") = "gzip, deflate, br"
http.SetRequestContent(data, "application/json")
http.Send("POST", "https://api.mailjet.com/v3.1/send")

and the same without RequestHeader("Authorization ») and using AuthenticationRequired event:

Always HTTP 401

I tried with Xojo 2019r2.1, same issue.

I tried using Chilkat plugin (macOS) and it works like a charm, same parameters.
If I could use it for iOS I would ;-(

Xojo documentation (?) or example(s) are not helping.
Debugging is more than limited as Xojo.Net.HttpSocket only exposes ‘ValidateCertificates’ …
From classic framework, URLConnection to Xojo.Net.Http every step forward (?) see less and less properties exposed, more confusion…

I tried that and it worked. It seems that most Base64 encode functions add line breaks after X characters. Basic Authentication Header must be a single line.

The following should work :slight_smile:

[code]http.ClearRequestHeaders

//data is a xojo.core.dictionary containing the json as described here https://dev.mailjet.com/email/reference/send-emails/
http.SetRequestContent( TextEncoding.UTF8.ConvertTextToData(xojo.data.GenerateJSON(data)), “application/json” )

Dim auth As Text = “Mailjet_APIKey:Mailjet_SecretKey” //Replace with values found in https://app.mailjet.com/account/api_keys
Dim authBase64 As Text = "Basic " + encodeBase64_NoLineBreaks(auth)

http.RequestHeader(“Authorization”) = authBase64

http.Send(“POST”, “https://api.mailjet.com/v3.1/send”)[/code]

[code]Public Function encodeBase64_NoLineBreaks(aText as Text) as Text
'By Jason King
'Function encodeBase64(aText as Text) As Text
Const FoundationLib = “Foundation.framework”

declare function dataUsingEncoding lib FoundationLib selector “dataUsingEncoding:” (obj_id as ptr, encoding as Integer) as ptr
declare function stringWithString lib FoundationLib selector “stringWithString:” (obj_id as ptr, str as CFStringRef) as ptr
declare function NSClassFromString lib FoundationLib (clsName as CFStringRef) as ptr

const NSUTF8StringEncoding = 4
dim str as Ptr = stringWithString(NSClassFromString(“NSString”), aText)
dim mData as ptr = dataUsingEncoding(str,NSUTF8StringEncoding)

declare function base64EncodedStringWithOptions lib FoundationLib selector “base64EncodedStringWithOptions:” _
(obj_id as ptr, options as Integer) as CFStringRef

Return base64EncodedStringWithOptions(mData,0)
'End Function
End Function
[/code]

Jeremie ! Faster than me :wink:
I just came to the same conclusion and I was rewriting the M_Text Encodebase64 for the same reason.

I just did a few tests using URLConnection and it’s working but URLConnection relies on Strings !

I’ll try your methods.

Many thanks !

Most grateful to you Jeremie !
It’s ok now.