I have "basic_auth" authentication working for a custom resource post request and now want to add "cookie" authentication. I checked both options on the "Settings for resource" page. But when I try to do the cookie authentication I get

echo '{"foo": "bar"}' | curl -d @- http://localhost/api/RESOURCE?_format=hal_json --header "Content-Type:application/json" --header "X-CSRF-Token:1234" -v
HTTP/1.1 401 Unauthorized
{"message":"No authentication credentials provided."}

If I disable basic_auth and just leave cookie auth do the same request I get

echo '{"foo": "bar"}' | curl -d @- http://localhost/api/RESOURCE?_format=hal_json --header "Content-Type:application/json" --header "X-CSRF-Token:1234" -v
HTTP/1.1 403 Forbidden
{"message":"The \u0027restful post RESOURCE_rest_resource\u0027 permission is required."}

Not sure why I'm getting a different error message but what do I need to do to get cookie auth working? If I go to the People -> Permissions page and enable "Access POST" on my resource for Anonymous users then the curl call works. But that seems to completely bypass any authentication so I don't want that. Here's the call after enabling "Access POST" for anon users:

echo '{"foo": "bar"}' | curl -d @- http://localhost/api/RESOURCE?_format=hal_json --header "Content-Type:application/json" -v
HTTP/1.1 201 Created

Comments

codesmith created an issue. See original summary.

wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

Are you sending a cookie with your request? I don't see it in your first curl example.

wim leers’s picture

Project: REST UI » Drupal core
Version: 8.x-1.15 » 8.4.x-dev
Component: User interface » rest.module
codesmith’s picture

Status: Postponed (maintainer needs more info) » Active

I'm sending it as a header:

--header "X-CSRF-Token:1234"

That should do it right? I saw this in /core/modules/rest/src/Tests/RESTTestBase.php

      case 'POST':
        $options += [
          'headers' => $csrf_token !== FALSE ? [
            'Content-Type' => $mime_type,
            'X-CSRF-Token' => ($csrf_token === NULL ? $requested_token : $csrf_token),
          ] : [
            'Content-Type' => $mime_type,
          ],
          'body' => $body,
        ];
        $response = $client->post($url, $options);
        break;

Thanks for the help!

wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

That's not a cookie, but a CSRF token. When using cookie authentication, you must indeed also send a CSRF token when doing POST/PATCH/DELETE requests (i.e. all requests that make changes), but you still need to send a cookie along with every request as well!

Browsers do this automatically for requests made by JS, but outside a browser, it's up to you!

codesmith’s picture

Status: Postponed (maintainer needs more info) » Active

Aha! Ok for some reason I was equating "cookie authentication" with providing the X-CSRF-Token header. Cookie auth is the cookie provided by the user module after a user logs in. I understand now but this leads me to:

1) If POSTing to a resource requires authentication, why do we need the X-CSRF-Token header?

2) Doesn't actually seem like the X-CSRF-Token is required anyway? I can do a POST with basic auth and not pass the X-CSRF-Token and it works.

echo '{"foo": "bar"}' | curl -d @- -u USER:PASSWORD http://localhost/api/RESOURCE --header "Content-Type:application/json" -v
HTTP/1.1 201 Created

3) The REST UI interface requires me to select an "Authentication provider" for POST and DELETE requests. However, if I give the Anonymous User permission to access those methods in the "RESTful Web Services," I can perform the request without authenticating. So seems like there's a disconnect there.

Thanks so much for the help!

codesmith’s picture

Title: Can't get cookie authentication working » Help with REST authentication
wim leers’s picture

  1. If POSTing to a resource requires authentication, why do we need the X-CSRF-Token header?

    "CSRF" = https://en.wikipedia.org/wiki/Cross-site_request_forgery. Requests made by clients running in a browser automatically include the cookie. So if a malicious user can somehow get a web app (which is written in JS, and runs in a browser) to perform an unsafe (POST/PATCH/DELETE) request by tricking the user of the web app, then you can actually attack them. The browser will NOT know to include additional request headers though. That's why we have this CSRF token request header. Just like we have a CSRF token in HTML forms, for the exact same reason.
    See #1891052: Protect write operations from CRSF by requiring an token (when using cookie/session-based authentication), where this was introduced.

  2. See above: the CSRF token is only required when using cookie authentication.
  3. I could not agree more that the REST UI module is misleading in that regard! That's why we have this issue in the REST UI module to fix that: #2332797: Add option to allow access to resource (or a particular method on a resource) without authentication (i.e. as anon). That is in turn sadly blocked on an issue in the REST module: #2817737: A REST resource's "auth" configuration MUST be non-empty, which prevents configuring it for anon access only. This part of Drupal/REST was poorly designed, unfortunately (if it was ever given a thought at all).
wim leers’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.