Last updated January 24, 2015. Created on August 29, 2013.
Edited by queenvictoria, tyler.frankenstein, ransomweaver, stovak. Log in to edit this page.

In the previous examples, we have used HTTP Basic authentication for all requests. You can also use other authentication protocols.

Core includes:

Contrib provides:

Enabling supported_auth

The auth method must be enabled for the specific resource and method. For example:

resources:
  'entity:node':
    GET:
      supported_formats:
        - json
      # Support both the core provided auth protocols.
      supported_auth:
        - cookie
        - http_basic

POST example with Guzzle and session cookies

Using session authentication for a POST request is a bit more complicated than HTTP Basic Authentication, because we need to provide a CSRF protection token. This is necessary to protect web browser users from malicious sites that could trigger RESTful POST requests on the user's behalf.

Example of POSTing a node with Guzzle version 4:

<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/core/vendor/autoload.php');

use
GuzzleHttp\Client;
use
GuzzleHttp\Exception\RequestException;

$base_url = 'http://example.com';

try {

 
$client = new Client([
   
'base_url' => $base_url,
   
'cookies' => true,
   
'allow_redirects' => true,
   
'debug' => true
   
]);
  
 
$response = $client->post("/user/login", [
   
'cookies' => true,
   
"body" => [
     
"name"=> "username",
     
"pass"=> "password",
     
'form_id' => 'user_login_form'
   
]
  ]);

 
$token = $client->get('rest/session/token', [
   
'cookies' => true
 
])->getBody(TRUE);

 
$token = (string)$token;

 
$node = array(
   
'_links' => array(
     
'type' => array(
       
'href' => $base_url . '/rest/type/node/page'
     
)
    ),
   
'title' => array(0 => array('value' => 'New node title')),
  );

 
$response = $client->post('entity/node', [
   
'cookies' => true,
   
'headers' => [
     
'Accept' => 'application/json',
     
'Content-type' => 'application/hal+json',
     
'X-CSRF-Token' => $token,
    ],
   
'json' => $node
 
]);
  if (
$response->getStatusCode() == 201) {
    print
'Node creation successful!';
  } else {
    print
"unsuccessful... keep trying";
   
print_r(get_defined_vars());
  }
} catch(
RequestException $e) {
  echo
$e->getRequest();
  echo
"\n\n";
     if (
$e->hasResponse()) {
         echo
$e->getResponse();
     }
}
?>

Cookie Auth, Views and User Relationships

Basic auth is not possible with Views. Cookie Auth is on by default and will provide context (e.g. an Authored By User relationship) to a view that needs to know about the logged-in user. To have this context, the connecting client application needs to provide the session cookie. See the preceding Guzzle example for how to login and set that cookie in the client. The method will be the same for any client platform (e.g. iOS using AFNetworking). After fetching the cookie by POSTing the name/pass to the /user endpoint, subsequent REST views requests can use User relationships.

GET example with cURL and HTTP Basic

Using HTTP Basic authentication for a GET request is quite straightforward. Given the following resource configuration, which allows GET access on nodes through HTTP Basic authentication and supports hal+json format:

resources:
  'entity:node':
    GET:
      supported_formats:
        - hal_json
      supported_auth:
        - basic_auth

Note: make sure that hal and basic_auth modules are enabled.

If a node is created, its nid is 1 and the Authenticated role has the permission Access GET on Content resource, we can make the following cURL request:

curl --request GET --user myusername:mypassword --header 'Accept: application/hal+json' \
http://d8.local/node/1

And the response should be something like this:

{"_links":{"self":{"href":"http:\/\/d8.local\/node\/1"},"type":{"href":"http:\/\/d8.local\/rest\/type\/node\/page"},"http:\/\/d8.local\/rest\/relation\/node\/page\/uid":[{"href":"http:\/\/d8.local\/user\/1","lang":"en"}],"http:\/\/d8.local\/rest\/relation\/node\/page\/revision_uid":[{"href":"http:\/\/d8.local\/user\/0"}]},"uuid":[{"value":"f8e0ab5f-8066-49cf-815e-94f8f38b172b"}],"type":[{"target_id":"page"}],"langcode":[{"value":"en"}],"title":[{"value":"asdfasdf","lang":"en"}],"_embedded":{"http:\/\/d8.local\/rest\/relation\/node\/page\/uid":[{"_links":{"self":{"href":"http:\/\/d8.local\/user\/1"},"type":{"href":"http:\/\/d8.local\/rest\/type\/user\/user"}},"uuid":[{"value":"d3fdfeaf-926f-4258-a905-5fe88f1065e2"}],"lang":"en"}],"http:\/\/d8.local\/rest\/relation\/node\/page\/revision_uid":[{"_links":{"self":{"href":"http:\/\/d8.local\/user\/0"},"type":{"href":"http:\/\/d8.local\/rest\/type\/user\/user"}},"uuid":[{"value":"2cb087e9-60f5-4bf9-9905-5d3dd34483c4"}]}]},"status":[{"value":"1","lang":"en"}],"created":[{"value":"1396992603","lang":"en"}],"changed":[{"value":"1396992608","lang":"en"}],"promote":[{"value":"0","lang":"en"}],"sticky":[{"value":"0","lang":"en"}],"revision_timestamp":[{"value":"0"}],"log":[{"value":"","lang":"en"}],"body":[{"value":"<p>asdfasfd<\/p>\r\n","format":"basic_html","summary":""}]}

Cookie Auth with JavaScript

Try POSTing to user/login and setting the Accept header to application/json, and setting the Content-type header to application/x-www-form-urlencoded. You may have to append the credentials to the path, for example: user/login?name=foo&pass=bar&form_id=user_login_form

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

stovak’s picture

Recently, d8 has switched from guzzle 3 to guzzle 4. This changes the namespace from Guzzle to GuzzleHttp. Version 4 also has subtle differences that effect the code.

I Re-did this example for Guzzle 4, but still having issues posting to d8 site. Giving me the following error: "The type of links must be defined." Will post update when I can make it go.

<?php
equire_once
(__DIR__."/../vendor/autoload.php");

use
GuzzleHttp\Client;
use
GuzzleHttp\Exception\RequestException;

try {
 
$client = new Client([
   
'base_url' => 'http://schedulify.local:8083',
   
'cookies' => true,
   
'allow_redirects' => false,
   
'debug' => true
   
]);
     
 
$resp = $client->post("/user", [
   
"body" => [
     
"username"=> "**********",
     
"password"=> "**********",
     
'form_id' => 'user_login_form'
   
]
  ]);
 
$token = $client->get('rest/session/token')->getBody(TRUE);
 
$token = (string)$token;
 
$node = array(
   
'_links' => array(
     
'type' => array(
       
'href' => 'http://drupal-8.localhost/rest/type/node/page'
     
)
    ),
   
'title' => array(0 => array('value' => 'New node title')),
  );
 
 
$response = $client->post('entity/node', array(
   
'headers' => [
     
'Accept' => 'application/json',
     
'Content-type' => 'application/hal+json',
     
'X-CSRF-Token' => $token,
    ],
   
'json' => json_encode($node)
  ));
  if (
$response->getStatusCode() == 201) {
    print
'Node creation successful!';
  } else {
    print
"unsuccessful... keep trying";
   
print_r(get_defined_vars());
  }
} catch(
RequestException $e) {
  echo
$e->getRequest();
     if (
$e->hasResponse()) {
         echo
$e->getResponse();
     }
}
?>
queenvictoria’s picture

Using your code as a starting point I've updated the code sample on this page so that it works. Things that needed changing.

  1. Path to login page is /user/login (not /user)
  2. Parameters are name and pass (not username and password)
  3. You don't encode the $node object (that's what Guzzle 'json' does)
  4. You need to pass 'cookie' => true on every request (importantly getting the token and creating the node). It's not enough to do it on the Client object.