I'm trying to make a POST request to create a node via ajax on the same domain as the Drupal site (no cross-domain action here). In following the example here, the response is always a 403.

The "Content" resource is enabled for POST requests with basic_auth & cookie authentication, and hal_json & json formats.

When trying to make the request via POSTMAN, putting in admin username and password hash into header as basic auth, it creates the node. So I don't think it is related to the actual creating of the node.

The account I am testing on for the ajax request is the same admin account, so this shouldn't be a permissions issue either.

I checked in CsrfRequestHeaderAccessCheck::access(), and it actually does return AccessResult::allowed()->setCacheMaxAge(0), so it is not failing at the CSRF token check. It appears to be failing somewhere else after that, with, \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException

Here is the code:

$('#create-node-submit').click(function(e) {
    e.preventDefault();
    var newNode = {
        _links: {
            type: {
                href: '/rest/type/node/article'
            }
        },
        type: {
            target_id: 'article'
        },
        title: {
            value: 'This is a test Article from REST'
        },
        field_description: {
            value: 'Here is some test description.'
        }
    };
    getCsrfToken(function (csrfToken) {
        postNode(csrfToken, newNode);
    });

    return false;
});

function getCsrfToken(callback) {
    $.get(Drupal.url('rest/session/token'))
        .done(function (data) {
            var csrfToken = data;
            callback(csrfToken);
        });
}

function postNode(csrfToken, node) {
    $.ajax({
        url: '/entity/node?_format=hal_json',
        method: 'POST',
        headers: {
            'Content-Type': 'application/hal+json',
            'X-CSRF-Token': csrfToken
        },
        data: JSON.stringify(node),
        success: function (node) {
            console.log(node);
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            console.log("Status: " + textStatus);
            console.log("Error: " + errorThrown);
        }
    });
}

The messages are not helpful:

Status: error
Error: Forbidden

Comments

cruno created an issue. See original summary.

cruno’s picture

Issue summary: View changes
wim leers’s picture

Category: Bug report » Support request
Status: Active » Postponed (maintainer needs more info)
Related issues: +#2808233: REST 403 responses don't tell the user *why* access is not granted: requires deep Drupal understanding to figure out

Yes, we're aware of the extremely frustrating error responses. We have #2808233: REST 403 responses don't tell the user *why* access is not granted: requires deep Drupal understanding to figure out to fix that.

But, I want to help you in the mean time. Can you post the full response that the server is sending? (jQuery.ajax() does crappy things in case of error responses, which makes this even harder to understand.)

cruno’s picture

Category: Support request » Bug report
Status: Postponed (maintainer needs more info) » Active
StatusFileSize
new133.69 KB
new6.3 KB
new28.03 KB
new15.95 KB

Wim Leers: I'm including screenshots of the response and request headers/data being sent and received.

cruno’s picture

Category: Bug report » Support request

Accidentally re-set the ticket category.

wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

Please export your rest.resource.entity.node REST Resource config entity and post it here.

cruno’s picture

Status: Postponed (maintainer needs more info) » Active

It's the default rest.resource.entity.node.yml file in the core rest module.

langcode: en
status: true
dependencies:
  module:
    - basic_auth
    - hal
    - node
id: entity.node
plugin_id: 'entity:node'
granularity: resource
configuration:
  methods:
    - GET
    - POST
    - PATCH
    - DELETE
  formats:
    - hal_json
  authentication:
    - basic_auth

From the db:

uuid: 36c6c926-b0d9-4a70-90e3-f7251a2fdd97
langcode: en
status: true
dependencies:
  module:
    - basic_auth
    - hal
    - node
_core:
  default_config_hash: t_jfECmZhJqBOJuSOFn87EOi_TWi-_fRYTuJgd19vgg
id: entity.node
plugin_id: 'entity:node'
granularity: resource
configuration:
  methods:
    - GET
    - POST
    - PATCH
    - DELETE
  formats:
    - hal_json
  authentication:
    - basic_auth
  POST:
    supported_formats:
      - hal_json
      - json
    supported_auth:
      - basic_auth
      - cookie
wim leers’s picture

Status: Active » Postponed (maintainer needs more info)

That also looks fine.

Last question: does this user have the appropriate create <TYPE> content?

cruno’s picture

Yes, the user is the admin.

wim leers’s picture

Damn :(

Then I'm afraid the only answer I can give you is this one:

  1. install & enable xdebug
  2. put a breakpoint in \Drupal\rest\Plugin\rest\resource\EntityResource::post()
  3. step through this code:
        if (!$entity->access('create')) {
          throw new AccessDeniedHttpException();
        }
    

    … so you can figure out the root cause

Very sorry. Until #2808233: REST 403 responses don't tell the user *why* access is not granted: requires deep Drupal understanding to figure out is done, this is the only solution.

wim leers’s picture

Oh there's one more thing I can check. Can you export your rest.settings and paste it here?

cruno’s picture

Thanks for your help. I'll try xdebug again.

rest.settings.yml:

link_domain: null
bc_entity_resource_permissions: false
_core:
  default_config_hash: bwcdqlollZ-bMAg90HtLMFFBgY7UXJohIln7BICIooE
wim leers’s picture

So #12 counters my last suspicion: that you had the BC layer for entity permissions enabled, which would've required an extra permission to be granted. (#2664780: Remove REST's resource- and verb-specific permissions for EntityResource, but provide BC and document why it's necessary for other resources)

Which means using xdebug to find the root cause is the only solution for now, I'm afraid :( Sorry! We're working hard to make this better!

cruno’s picture

Status: Postponed (maintainer needs more info) » Closed (works as designed)

The issue turned out to be that Rest UI would not set the authentication in the configuration properly. supported_auth can be set, but authentication cannot.
In rest.resource.entity.node.yml:
Before:

uuid: 36c6c926-b0d9-4a70-90e3-f7251a2fdd97
langcode: en
status: true
dependencies:
  module:
    - basic_auth
    - hal
    - node
_core:
  default_config_hash: t_jfECmZhJqBOJuSOFn87EOi_TWi-_fRYTuJgd19vgg
id: entity.node
plugin_id: 'entity:node'
granularity: resource
configuration:
  methods:
    - GET
    - POST
    - PATCH
    - DELETE
  formats:
    - hal_json
  authentication:
    - basic_auth
  POST:
    supported_formats:
      - hal_json
      - json
    supported_auth:
      - cookie

After:

uuid: 36c6c926-b0d9-4a70-90e3-f7251a2fdd97
langcode: en
status: true
dependencies:
  module:
    - basic_auth
    - hal
    - node
_core:
  default_config_hash: t_jfECmZhJqBOJuSOFn87EOi_TWi-_fRYTuJgd19vgg
id: entity.node
plugin_id: 'entity:node'
granularity: resource
configuration:
  methods:
    - GET
    - POST
    - PATCH
    - DELETE
  formats:
    - hal_json
  authentication:
    - cookie
  POST:
    supported_formats:
      - hal_json
      - json
    supported_auth:
      - cookie

So as it turns out the issue was with Rest UI module, not core Rest module.

gvso’s picture

In case someone else faces this problem, there is an issue about this on REST UI issue queue #2831716: REST UI does not support "resource" granularity