User Authentication (Session based) on Ghost (Pro)?

Hi everyone,
We’re developing a custom workflow for a client’s Ghost instance to manage advertisements. We need to work with the Ghost Admin API, and we decided to use user authentication because it’s simple for the Ghost owner to enter their email address and password into a custom form to get a session cookie and make changes. Our solution works on local development and on a self-hosted server, but it doesn’t work on Ghost(pro). I suspect that Ghost(pro) is not setting all of the necessary CORS headers.

Here are 2 functions, login procedure finish successful on Ghost (pro) and return status code 201 and set up session cookie.

However when we try to make a connection, we use testAuth function to check users, it fails.
Error in browser console is:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.ghost.io/ghost/api/admin/users/. (Reason: expected ‘true’ in CORS header ‘Access-Control-Allow-Credentials’)

Code showcase:

const BASE_DOMAIN = 'https://www.example.com/';
const BASE_URL = `https://example.ghost.io/ghost/api/admin/`;
 /*
* Login procedure
--------------------------------------------*/
const login = async(login, password) => {
    try{
        let res = await fetch(BASE_URL + 'session/',{
            method:'POST',
            headers:{
                "Content-Type": "application/json",
                "Origin": BASE_DOMAIN,
                "Accept-Version": "v3.0"
            },
            body:JSON.stringify({"username": login, "password": password})
        })

        if(res.status == 401){
            throw new Error('Unauthorized, email or password does not match');
        }
        if(res.status == 201){
            console.log('[*] We are logged-in');
        }

    }catch(err){
        console.log('[X] err ', err.message);
    }    
}



/*
* Test Auth state on getting user list
--------------------------------------------*/
const testAuth = async() =>{
    try{
        let res = await fetch(BASE_URL + 'users/',{
            method:'GET',
            credentials: 'include',
            headers:{
                "Content-Type": "application/json",
                "Origin": BASE_DOMAIN,
                "Accept-Version": "v3.0"
            }
        })
        if (res.status != 200){
            throw new Error(‘forbidden’);
        }else{
            return 'ok'
        }
    }catch(err){
        console.log('[X] err ', err.message);
    }
}

I’ve read somewhere, that it is more reliable to use Token authentication.
Thank you in advance for any advice.

Tom

Try adding ‘mode: cors’ on your fetch request.

1 Like

Hi Cathy,

thank you for fast reply. I tried to add it but it has still the same error. No change.

Yeah, I’m suspecting you’re not going to be able to get the browser to do this - it’s pretty similar to various cookie theft strategies. I’ve done session authentication, but I’ve done it with a cloud function, so it’s Node making the requests, not the browser. (Node doesn’t care about cors.) You could also look at something like running a proxy that rewrites the headers to include the one your browser wants.

But tokens work great in browsers, and if you use the SDK (which covers a lot of functionality), they’re pretty painless.