hasura / graphql-engine

Blazing fast, instant realtime GraphQL APIs on your DB with fine grained access control, also trigger webhooks on database events.
https://hasura.io
Apache License 2.0
31.02k stars 2.76k forks source link

Missing cookies between Hasura and auth hook? #3855

Open jpetitcolas opened 4 years ago

jpetitcolas commented 4 years ago

I am currently struggling with authentication hook. I have some HTTP-only cookies containing my access token. As Hasura doesn't support token from cookies, but only Authorization header, I planned to set up an hook to read cookies and return data required by Hasura (user ID and role).

Testing my auth hook independently works:

curl -X POST \
  https://auth.acme.com/auth \
  -H 'Cookie: access_token=XXX;'
{
    "X-Hasura-User-Id": "42",
    "X-Hasura-Role": "user"
}

Yet, if I test with my Hasura endpoint, I can see in the logs:

curl -X POST \
  https://graphql.acme.com/v1/graphql \
  -H 'Cookie: access_token=XXX;' \
  -d '{"operationName":"getFoos","variables":{},"query":"query getFoos {\n  foos { id } }"}'

I got an error from webhook:

{
    "type": "webhook-log",
    "timestamp": "2020-02-09T18:16:43.370+0000",
    "level": "error",
    "detail": {
        "response": "{\"error\":\"Missing `access_token` cookie\"}",
        "url": "https://auth.acme.com/auth",
        "method": "POST",
        "http_error": null,
        "status_code": 401
    }
}

It looks like the cookies are not transferred between GraphQL Engine and auth hook. My auth code is the following (running on AWS Lambda):

require('source-map-support').install();

const jwt = require('jsonwebtoken');

export const getCookiesFromHeader = headers => {
    if (headers === null || headers === undefined || headers.Cookie === undefined) {
        return {};
    }

    // Split a cookie string in an array (Originally found http://stackoverflow.com/a/3409200/1427439)
    var list = {},
        rc = headers.Cookie;

    rc && rc.split(';').forEach(function( cookie ) {
        var parts = cookie.split('=');
        var key = parts.shift().trim()

        try {
            var value = decodeURIComponent(parts.join('='));
            if (key != '') {
                list[key] = value
            }
        } catch (err) {
            console.error(`Decoding error for ${key} (${value}): ${err.message}`)
        }
    });

    return list;
};

export const handler = async (event) => {
    const cookies = getCookiesFromHeader(event.headers);
    const { access_token: accessToken } = cookies;
    if (!accessToken) {
        return {
            statusCode: 401,
            body: JSON.stringify({
                "error": "Missing `access_token` cookie"
            })
        };
    }

    let decodedToken = null;

    try {
        decodedToken = jwt.verify(accessToken, process.env.AUTH0_PEM);
    } catch (err) {
        return {
            statusCode: 401,
            body: JSON.stringify({
                error: err.message
            })
        };
    }

    const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'];

    return {
        statusCode: 200,
        body: JSON.stringify({
            "X-Hasura-User-Id": hasuraClaims['x-hasura-user-id'],
            "X-Hasura-Role": hasuraClaims['x-hasura-default-role']
        })
    }
}

It works locally, but not once deployed.

Is there any restrictions for passing cookies? How can I debug the request to the auth hook? I tried using the debug log level, in vain. And I never read any Haskell before, reducing a little bit my understanding of current code base. :)

leoalves commented 4 years ago

@jpetitcolas,

Hasura Auth Webhook in POST request mode will send the headers in the body of the request. https://docs.hasura.io/1.0/graphql/manual/auth/authentication/webhook.html#post-request

rolandschellhorn commented 4 years ago

I have the same problem. I want to pass my http only cookies to my webhook api. I use post and read the payload. Any guesses? Should this work?

Edit: Since it is stored inside the body - it looks like this will not work with a http only cookie.

zakybilfagih commented 3 years ago

I have the same problem. I want to pass my http only cookies to my webhook api. I use post and read the payload. Any guesses? Should this work?

Edit: Since it is stored inside the body - it looks like this will not work with a http only cookie.

HTTP only cookie will be sent to the action webhook, you just need to enable forward headers on the action modify tab. Also make sure that the action is of type mutation since query type doesn't seem to work/

samuela commented 3 years ago

@mackarelfish This issue is in reference to authentication webooks, not action webhooks. AFAIU they behave quite differently.

LukasDeco commented 2 weeks ago

Is this still an issue? I am examining using http-only cookies to send a token to hasura and read it, but it's looking here like that might not be an option?