B4J Question User/Pass not being sent correctly with HTTPJob

aaronk

Well-Known Member
Licensed User
Longtime User
Hi,

I am trying to work out how to PUT a command to a URL.

I am using a nonUI app.

So far I have:

B4X:
Sub AppStart (Args() As String)
   
    Run

    StartMessageLoop
 
End Sub

Private Sub Run

    Dim job1 As HttpJob    ' Lib jOKHttpUtils2_NONUI v2.62

    Dim URL As String = "https://restapi.URL.HERE"
    Dim userName As String = "MyUsername"
    Dim password As String = "MyPassword"

    Dim MyString As String
    MyString = $"{
  "status": "DEACTIVATED"
}"$

    job1.Initialize("JOB1", Me)
    job1.Username = userName
    job1.Password = password
    job1.PutString(URL,MyString)
   
    Wait for JobDone (Job As HttpJob)
    If Job.Success = True Then
        Log(Job.GetString)
    End If
    Job.Release
   
End Sub

This will return:
ResponseError. Reason: Unauthorized, Response: {"errorMessage":"Invalid credentials","errorCode":"10000001"}

Based on the documentation it looks like my username and password wasn't accepted but I know I am differently using the correct username and password.

The documentation explains how to do it in Node.js:
B4X:
var request = require('request');
var body = [];
var auth = "Basic " + new Buffer("username:password").toString("base64");
request({
    method: 'PUT',
    url: 'https://restapi.URL.HERE',
    headers : {"Authorization" : auth},
    body: {"status":"DEACTIVATED"},
    json: true
},
    function (error, response, body) {
        if(error) {
            console.log('Error:', error);
            return;
        } else {
            // return statusCode
            console.log(response.statusCode);
            // return contentType
            console.log(response.headers['content-type']);
            console.log(body);
        }
    }
)


curl -X PUT --header "Content-Type: application/json" --header "Accept: application/json" --header "Authorization: Basic QWFyb25xxxxxxxxxxxxxx1YzZkYw==" -d "{
\"status\": \"DEACTIVATED\"
}" "https://restapi.URL.HERE"

I am guessing there is something wrong with my B4J code ?
 

aaronk

Well-Known Member
Licensed User
Longtime User
Just worked out I need to use the API key part of the username.

  1. Combine the user name and API Key into a single string with a colon separating the values. For example, if the user name is starterkit and the APIKey is d703f52b-1200-4318-ae0d-0f6092b2e6ab, the concatenated string would be:
    starterkit:d703f52b-1200-4318-ae0d-0f6092b2e6ab
  2. Encode the concatenated string using Base64 (i.e. RFC2045-MIME):
    c3RhcnRlcmtpdDpkNzAzZjUyYi0xMjAwLTQzMTgtYWUwZC0wZjYw
    OTJiMmU2YWI=
  3. Set the Authorization header value to Basic followed the encoded string from step 2. Make sure there is a space between Basic and the encoded string:
    Basic c3RhcnRlcmtpdDpkNzAzZjUyYi0xMjAwLTQzMTgtYWUwZC0w
    ZjYwOTJiMmU2YWI=
Any ideas on how to combine it?

I know I could do step 1 by using:
B4X:
Dim api As String = "d703f52b-1200-4318-ae0d-0f6092b2e6ab"
    userName = userName & ":" & api

But how do I do step 2 & 3 ?

I am guessing step 3 above is automatic when I send the user/pass like I did in post 1 ?

I have now tried:
B4X:
Private Sub Run

    Dim job1 As HttpJob    ' Lib jOKHttpUtils2_NONUI v2.62

    Dim URL As String = ""https://restapi.URL.HERE""
    Dim userName As String = "MyUsername"
    Dim password As String = "MyPassword"

    Dim MyString As String
    MyString = $"{
  "status": "DEACTIVATED"
}"$
  
    Dim api As String = "d703f52b-1200-4318-ae0d-0f6092b2e6ab"
    userName = userName & "" & api
    
    Dim su As StringUtils    'jStringUtils v1.00
    Dim MyBase64StringAsBytes() As Byte = su.DecodeBase64(userName)
    userName = BytesToString(MyBase64StringAsBytes, 0, MyBase64StringAsBytes.Length, "UTF8")
    
    
    job1.Initialize("JOB1", Me)
    job1.Username = userName
    job1.Password = password

    job1.PutString(URL,MyString)
    
    Wait for JobDone (Job As HttpJob)
    If Job.Success = True Then
        Log(Job.GetString)
    End If
    Job.Release
    
End Sub

But when I run it, it comes up with an error:
Waiting for debugger to connect...
Program started.
Error occurred on line: 36 (Main)
java.io.IOException: Bad Base64 input character decimal 45 in array position 17
at anywheresoftware.b4a.objects.Base64.decode(Base64.java:1204)
at anywheresoftware.b4a.objects.Base64.decode(Base64.java:1259)
at anywheresoftware.b4a.objects.Base64.decode(Base64.java:1227)
at anywheresoftware.b4a.objects.StringUtils.DecodeBase64(StringUtils.java:36)
at b4j.example.main$ResumableSub_Run.resume(main.java:132)
at b4j.example.main._run(main.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:625)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:234)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:168)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:90)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:94)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:77)
at b4j.example.main.main(main.java:29)

Line 36 is

B4X:
Dim MyBase64StringAsBytes() As Byte = su.DecodeBase64(username)

I am guessing I am doing the Base64 wrong?
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
B4X:
Dim base64 as string = su.EncodeBase64(MyBase64StringAsBytes)
where su is stringutils

Similar methods should be available in ByteConverter or Encryption lib.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Combine the user name and API Key into a single string with a colon separating the values. For example, if the user name is starterkit and the APIKey is d703f52b-1200-4318-ae0d-0f6092b2e6ab, the concatenated string would be:
starterkit:d703f52b-1200-4318-ae0d-0f6092b2e6ab
userName = userName & "" & api
These two things do not match
 
Upvote 0

aaronk

Well-Known Member
Licensed User
Longtime User
Dim base64 as string = su.EncodeBase64(MyBase64StringAsBytes)
where su is stringutils

when I add that, it comes up with an error:
Cannot cast type: {Type=String,Rank=0, RemoteObject=True} to: {Type=Byte,Rank=1, RemoteObject=True}

These two things do not match

I have it now as the following while I test it:
B4X:
userName = "starterkit:d703f52b-1200-4318-ae0d-0f6092b2e6ab"
 
Upvote 0

aaronk

Well-Known Member
Licensed User
Longtime User
Just tried using:
B4X:
Dim base64 As String = su.EncodeBase64(userName.GetBytes("UTF8"))

I have changed my username and password to the correct user/pass an API key, but it still returns:
ResponseError. Reason: Unauthorized, Response: {"errorMessage":"Invalid credentials","errorCode":"10000001"}
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
So is the password the API key? Your sending userName:API and Password, not just userName:API. Also, Basic authentication already does the base64 encoding, so now you are encoding Base64 with Base64.
 
Upvote 0

aaronk

Well-Known Member
Licensed User
Longtime User
So is the password the API key? Your sending userName:API and Password
Just noticed that.

Yes I tried username being the username and the password being the API key and it looks like it accepted the login.
Now it's showing an internal error. I think it's because I need to set the content type to be Application/json.
 
Upvote 0

aaronk

Well-Known Member
Licensed User
Longtime User
Got it to work. Had to set the content type.

B4X:
job1.Username = userName
    job1.Password = password
        
    job1.PutString(URL,MyString)
    job1.GetRequest.SetContentType("application/json")    'add okHTTP lib
 
Upvote 0
Top