proyecto26 / RestClient

🦄 A Promise based REST and HTTP client for Unity 🎮
https://assetstore.unity.com/packages/slug/102501
MIT License
1.25k stars 173 forks source link

Directus Auth - 400 bad request using rest client but functional old school way?? #248

Open kiritodragneel opened 4 months ago

kiritodragneel commented 4 months ago

Hey, so I am trying to connect and get an access Token from my directus instance. If I use this code the code below then I get a 400 bad request error.

private async Task AuthenticateUserRest() {
        var url = "https://directus.mydomain.uk/auth/login";
        var email = "myemail@mydomain.com";
        var password = "Mysupersecurepassword!";
        var mode = "cookie";

        //Tried the json as a string seen in below example, made no difference at all
        JSON requestBody = new JSON();
        requestBody.Add("email", email);
        requestBody.Add("password", password);
        requestBody.Add("mode", mode);

        RestClient.Request(new RequestHelper {
            Uri = url,
            Method = "POST",
            Headers = new Dictionary<string, string> {
                { "Accept", "application/json, text/plain, */*" }
            },
            ContentType = "application/json",
            Body = requestBody,
            Retries = 32
        }).Then(response => {
            if (response.StatusCode == 200) {
                Debug.Log("Response data: " + response.Text);
                var responseJSON = JSON.ParseString(response.Text);
                TOKEN = responseJSON.GetJSON("data").GetString("access_token");
                RestClient.DefaultRequestHeaders["Authorization"] = "Bearer " + TOKEN;
            } else {
                Debug.Log("Error data: " + response.Text);
            }
        }).Catch(err => {
            Debug.LogError("Error: " + err.Message);
        });
    }

However if i use this snippet then it works without issue


 private async Task AuthenticateUser() {
        var url = "https://directus.mydomain.uk/auth/login";
        var email = "myemail@mydomain.com";
        var password = "mysupersecurepassword!";
        var mode = "cookie";
        var json = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"mode\":\"{mode}\"}}";
        var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Accept", "application/json, text/plain, */*");

        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await client.PostAsync(url, content);

        if (response.IsSuccessStatusCode){
            var responseData = await response.Content.ReadAsStringAsync();
            Debug.Log("Response data: " + responseData);
            JSON _responseJSON = JSON.ParseString(responseData);
            TOKEN = _responseJSON.GetJSON("data").GetString("access_token");
        }else{
            Console.WriteLine("Error: " + response.StatusCode);
            var errorData = await response.Content.ReadAsStringAsync();
            Debug.Log("Error data: " + errorData);
        }
    }
jdnichollsc commented 4 months ago

Hey dude, what's the code of that JSON class?

kiritodragneel commented 4 months ago

Hey, so I did try var json = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"mode\":\"{mode}\"}}";

thinking something similar, however it still did not work, but it is this asset https://assetstore.unity.com/packages/tools/input-management/total-json-130344

If it helps, if you add me on discord .muttley I can give you a username/password and my real domain so you can test too.

jdnichollsc commented 4 months ago

Hey mate, as I know Body is only going to work with Serializable classes using the Unity utility internally, if you want to use another tools for JSON serialization I recommend using BodyString attribute instead 🫡

kiritodragneel commented 4 months ago

Hey mate, as I know Body is only going to work with Serializable classes using the Unity utility internally, if you want to use another tools for JSON serialization I recommend using BodyString attribute instead 🫡

So even if i change the body to this Body = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"mode\":\"{mode}\"}}",

I still get HTTP/1.1 Bad Request.

In the interest of trial and error, I have made it like this, the same json code that works with the mentioned example above.

    private async Task AuthenticateUserRest() {
        var url = "https://directus.mydomain.uk/auth/login";
        var email = "richard@mydomain.com";
        var password = "mypassword!";
        var mode = "cookie";
        var json = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"mode\":\"{mode}\"}}";

        RestClient.Request(new RequestHelper {
            Uri = url,
            Method = "POST",
            Headers = new Dictionary<string, string> {
                { "Accept", "application/json, text/plain, */*" }
            },
            ContentType = "application/json, text/plain, */*",
            Body = new StringContent(json, Encoding.UTF8, "application/json"),
            Retries = 32
        }).Then(response => {
            if (response.StatusCode == 200) {
                Debug.Log("Response data: " + response.Text);
                var responseJSON = JSON.ParseString(response.Text);
                TOKEN = responseJSON.GetJSON("data").GetString("access_token");
                RestClient.DefaultRequestHeaders["Authorization"] = "Bearer " + TOKEN;
            } else {
                Debug.Log("Error data: " + response.Text);
            }
        }).Catch(err => {
            Debug.LogError("Error: " + err.Message);
        });
    }
kiritodragneel commented 4 months ago

Okay so here is the full class code, hopefully it can help

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Leguar.TotalJSON;
using Proyecto26;
using TMPro;
using UnityEngine;

public class DirectusLinkTesting : MonoBehaviour {
    [SerializeField] TMP_Text result;
    [SerializeField] string URL;
    [SerializeField] private string TOKEN;

    private string email = "richard@domain.com";
    private string password = "mypassword";
    private string mode = "cookie";

    private async void Start() {
        await AuthenticateUserRest();
    }

    public void FetchData() {
        RestClient.DefaultRequestHeaders["Authorization"] = "Bearer " + TOKEN;
        RestClient.Get(new RequestHelper {
            Uri = URL,
        }).Then(response => {
            LoadData(response.Text);
        }).Catch(err => {
            Debug.LogError("Error: " + err.Message);
        });
    }

    void LoadData(string _response) {
        result.text = _response;
    }

    private async Task AuthenticateUser() {
        var url = "https://directus.mydomain.uk/auth/login";
        var json = $"{{\"email\":\"{email}\",\"password\":\"{password}\",\"mode\":\"{mode}\"}}";
        var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Accept", "application/json, text/plain, */*");

        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await client.PostAsync(url, content);

        if (response.IsSuccessStatusCode){
            var responseData = await response.Content.ReadAsStringAsync();
            Debug.Log("Response data: " + responseData);
            JSON _responseJSON = JSON.ParseString(responseData);
            TOKEN = _responseJSON.GetJSON("data").GetString("access_token");
        }else{
            Console.WriteLine("Error: " + response.StatusCode);
            var errorData = await response.Content.ReadAsStringAsync();
            Debug.Log("Error data: " + errorData);
        }
    }

    private async Task AuthenticateUserRest() {
        var loginurl = "https://directus.mydomain.uk/auth/login";
        var requestBody = new {
            email = email,
            password = password,
            mode = mode
        };

        RestClient.Request(new RequestHelper {
            Uri = loginurl,
            Method = "POST",
            Headers = new Dictionary<string, string> {
                { "Accept", "application/json, text/plain, */*" },
                { "Content-Type", "application/json" }
            },
            Body = JsonUtility.ToJson(requestBody),
            Retries = 3 
        }).Then(response => {
            if (response.StatusCode == 200) {
                Debug.Log("Response data: " + response.Text);
                var responseJSON = JSON.ParseString(response.Text);
                TOKEN = responseJSON.GetJSON("data").GetString("access_token");
                RestClient.DefaultRequestHeaders["Authorization"] = "Bearer " + TOKEN;
            } else {
                Debug.Log("Error data: " + response.Text);
            }
        }).Catch(err => {
            Debug.LogError("Error: " + err.Message);
        });
    }
}

I have AuthenticateUser() which works fine, that runs, and then i fetch data no issues, however trying to use AuthenticateUserRest always gets a 400 error, no matter what way i provide it the body, I get the same error, I changed how I gave it the content type, retries, everything I am at a loss.

kiritodragneel commented 4 months ago

Just bumping this as still got same issue and can't find a fix

maifeeulasad commented 2 months ago

@kiritodragneel care to share it as a toy project?

Willing to help you, but it taks quite a while to setup the excat same thing.

GitHub would be best way to share your project (Only share the necessary part).

Thanks.