'LaravelPhp Sanctum Login Authentication Android Java

I have a fully working SPA website built with LaravelPhp 8 Sanctum authentication and Vuejs. Now I'm building an Android app that uses the same APIs. Connecting to APIs that don't require authentication works perfectly but protected APIs don't. I send POST to login and it works but after that no other protected API work. It returns error 401 (x-android-response-source: NETWORK 401) Do I use a session cookie and then how do I set a session cookie? Thank you.

this is how SPA works:

enter image description here

Here is config/auth.php (on API it says token but I never used tokens in my SPA)

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

routes/api.php

 Route::post('login', ['as' => 'login', 'uses' => 'App\Http\Controllers\LoginController@login']);

    Route::middleware(['auth:sanctum'])->group(function () {
            Route::get('customer', 'App\Http\Controllers\CustomerController@show');
}

.env:

SANCTUM_STATEFUL_DOMAINS=mywebsite.si
SESSION_DOMAIN=.mywebsite.si

BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

(Android) Http.java

public class Http {
    Context context;
    private String url, method = "GET", data = null, response = null;
    private Integer statusCode = 0;
    private LocalStorage localStorage;

    public Http(Context context, String url) {
        this.context = context;
        this.url = url;
        localStorage = new LocalStorage(context);

    }

    public void setMethod(String method) {
        this.method = method.toUpperCase();
    }

    public void setData(String data) {
        this.data = data;
    }   

    public String getResponse() {
        return response;
    }

    public Integer getStatusCode() {
        return statusCode;
    }

    public void send() {
        try {
            URL sUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) sUrl.openConnection();
            connection.setRequestMethod(method);
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("X-Requested-With", "XMLHttpRequest");
            connection.setRequestProperty("Cookie", "Access-Control-Allow-Credentials=true; Access-Control-Allow-Origin=https://mywebsite.si;");                           
            if (!method.equals("GET")) {
                connection.setDoOutput(true);
            }
            if (data != null) {
                OutputStream os = connection.getOutputStream();
                os.write(data.getBytes());
                os.flush();
                os.close();
            }
            statusCode = connection.getResponseCode();
            InputStreamReader isr;
            if (statusCode >= 200 && statusCode <= 299) {
                // if success response
                isr = new InputStreamReader(connection.getInputStream());
            } else {
                // if error response
                isr = new InputStreamReader(connection.getErrorStream());
            }
            BufferedReader br = new BufferedReader(isr);
            StringBuffer sb = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            response = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

LoginActivity:

String data = params.toString();
String url = getString(R.string.api_server) + "/login";

        new Thread(new Runnable() {
            @Override
            public void run() {
                Http http = new Http(LoginActivity.this, url);
                http.setMethod("post");
                http.setData(data);
                http.send();

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Integer code = http.getStatusCode();
                        if (code == 200) {
                            try {
                                JSONObject response = new JSONObject(http.getResponse());
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else if (code == 422) {
                            try {
                                JSONObject response = new JSONObject(http.getResponse());
                                String msg = response.getString("message");
                                alertFail(msg);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else if (code == 401) {
                            try {
                                JSONObject response = new JSONObject(http.getResponse());
                                String msg = response.getString("message");
                                alertFail(msg);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Toast.makeText(LoginActivity.this, "Error " + code, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();
    

UserActivity:

String url = getString(R.string.api_server) + "/customer";
        new Thread(new Runnable() {
            @Override
            public void run() {
                Http http = new Http(UserActivity.this, url);                
                http.send();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Integer code = http.getStatusCode();
                        if (code == 200) {
                            try {
                                JSONObject response = new JSONObject(http.getResponse());
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        } else {
                            Toast.makeText(UserActivity.this, "Error " + code, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();
    }

Response from login:

cache-control: no-cache, private
connection: Keep-Alive
content-type: application/json
date: Tue, 24 May 2022 10:19:21 GMT
keep-alive: timeout=5, max=100    
transfer-encoding: chunked
vary: Origin
x-android-received-millis: 1653387298665
x-android-response-source: NETWORK 200
x-android-selected-protocol: http/1.1
x-android-sent-millis: 1653387298552
x-ratelimit-limit: 20
x-ratelimit-remaining: 18


Solution 1:[1]

You have to set header for auth:sanctum protected apis

Authorization: Bearer <token-here> if you're using sanctum in proper way you can generate token against auth models and use those to fetch

Have a look into this article https://www.twilio.com/blog/build-restful-api-php-laravel-sanctum

Sanctum automatically checks the header and authenticate the user based on the token

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Akhzar Javed