19

Do anyone have a working REST Login on Drupal 8?

This is what I tried.

POST /user/login HTTP/1.1
Host: 8.d8.local
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: http://nikhilmohan.in
Cache-Control: no-cache

name=test&pass=password&form_id=user_login_form

It returns me HTML instead of JSON.

7 Answers 7

21

Staring from 8.2, Drupal supports json endpoints for Cookie authentication. You don't need to post the form anymore 🎉

curl --header "Content-type: application/json" --request POST \
  --data '{"name":"admin", "pass":"admin"}' \
http://drupal.d8/user/login?_format=json

Output will look like

{"current_user":{"uid":"1","roles":["authenticated","administrator"],"name":"admin"},"csrf_token":"wBr9ldleaUhmP4CgVh7PiyyxgNn_ig8GgAan9-Ul3Lg","logout_token":"tEulBvihW1SUkrnbCERWmK2jr1JEN_mRAQIdNNhhIDc"}

Change record: https://www.drupal.org/node/2720655

Other authentication methods: https://www.drupal.org/docs/8/core/modules/rest/using-other-authentication-protocols

3
  • I cannot get this to work, I get 403 "This route can only be accessed by anonymous users." strange as I'm using REST obviously not logged in
    – jim smith
    Feb 6, 2018 at 21:43
  • 1
    @jimsmith What are you using to test the call? I have had this problem before using Postman because it was getting my Chrome Cookies and saying I was logged in. You can test this by logging out in the browser and sending the request again Jun 11, 2018 at 9:35
  • 1
    When I run this curl command, I get HTML as the response, any clue on why?
    – BlondeSwan
    Jan 20, 2021 at 19:05
15

Here's how you can login via JavaScript for Drupal 8 REST:

Drupal 8.2 and beyond

  • POST: http://example.com/user/login?_format=json
  • Content-type: application/json
  • Data: { "name": "admin", "pass": "myPassword" }
  • Response: 200 OK

This will properly login via cookie authentication, and return a result similar to this:

{
  "current_user": {
    "uid":"1",
    "roles":["authenticated"],
    "name":"admin"
  },
  "csrf_token":"abc123",
  "logout_token":"def456"
}

I've created a contrib module called jDrupal that makes it very easy to login with JavaScript (among other things):

// Login and show the user their id.
jDrupal.userLogin('admin', 'myPassword').then(function() {
  alert(jDrupal.currentUser().id());
});

Prior to Drupal 8.2

  • POST: http://example.com/user/login
  • Content-type: application/x-www-form-urlencoded
  • Data: name=admin&pass=myPassword&form_id=user_login_form
  • Response: 200 OK | 303 See Other

You'll send the data along in the URL as a query string. The result will be HTML, so it won't return anything useful to you, but it will properly login via cookie authentication.

4
  • So returning HTML is inevitable ?
    – niksmac
    Jan 6, 2016 at 7:13
  • At this point AFAIK, yes HTML is inevitable. I'd imagine this will be improved over time, because for example there isn't yet a way to register a user through REST, but an issue has been made. Jan 6, 2016 at 13:57
  • it's not worked for me, is is required use Basic Authentication too?
    – Yuseferi
    Jul 12, 2016 at 12:08
  • FYI, JSON is returned as of Drupal 8.2, so no more HTML is returned. Dec 5, 2016 at 5:12
9
  1. A HTTP request is not RESTful based upon Content-Type.
  2. "REST Login" is technically an oxymoron.

RESTful authentication means to send authentication with each request because it is stateless. The example provided by Drupal 8 core is the Basic Auth module, which allows to send authentication credentials for a HTTP request via Basic HTTP Authentication given a user with permission to access Content via GET.

RESTful Example

Curl: curl -vvv -k -H "Authorization: Basic test:password" http://8.d8.local/node/1?_format=json

GET /node/1?_format=json HTTP/1.1
Host: 8.d8.local
User-Agent: curl/7.43.0
Accept: */*
Authorization: Basic test:password

However this is usually not good enough. The simple_oauth and oauth contrib modules provide OAuth 2 and 1 support respectively., with which a HTTP request can be made with OAuth authentication tokens based on the OAuth work flows described in those modules.

But the real question seems to be

How do I login via a Web Services API?

There is not a stable Drupal 8 module to do so, but the Services module provides methods for creating non-RESTful actions and targeted actions such as "login".

The following works after setting up an endpoint called "api":

Curl: curl -vvv -k -H "Content-Type: application/json" -H "Accept: application/json" -d '{"username": "test", "password": "password"}' http://8.d8.local/api/user/login

POST /api/user/login HTTP/1.1
Host: 8.d8.local
Accept: application/json
Content-Type: application/json
Content-Length: 44

{"username": "test", "password": "password"}

This returns JSON session id and name (also set in the response's Set-Cookie header).

and also you can login with Jquery ajax call with following snippet

$.ajax({
    url : "http://gttc.dd:8083/user/login",
    type : 'post',
    data : 'form_id=user_login_form&name=' + encodeURIComponent("username") + '&pass=' + encodeURIComponent("password"),
    dataType : 'json',
    error : function(data) {
            //error code
    },
    success : function(data) {
      console.log(data);
        //success code
    }
});
2
  • Services seems cool, however Drupal core is messed up in D8 IMO. there is a lot more to come.
    – niksmac
    Jan 2, 2016 at 7:24
  • 1
    Since Drupal 8.2 you can (and should) use the method described in drupal.stackexchange.com/a/221045/13237
    – andeersg
    Feb 13, 2017 at 13:37
4

Drupal Core version: 8.x-4.x

You need to enable the user login service first thing, this may be accomplished in so many ways, I prefer using REST UI module.

Go to /admin/config/services/rest and enable User Rest resource.

Once enabled it you can go to /admin/config/services/rest/resource/entity%3Auser/edit by clicking on Edit next to the User resource. Make sure to enable the GET method.

enter image description here

Now you have everything setup, you can start using the service by running this command in the terminal or by using any application for curl requests like: Postman and Restlet clients.

NOTE: CSRF Token can be obtained from: /rest/session/token

curl -i -L -X POST \
  -H "Content-Type:application/json" \
  -H "Accept:application/json" \
  -H "X-CSRF-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
  -d \
     '{
       "name": "my_username",
       "pass": "my_password"
     }' \
'http://SITE-URL/user/login?_format=json'

The return objects are as below:

SUCCESS:

{
  "current_user": {
  "uid": "1",
    "roles": [
      "authenticated"
    ],
    "name": "Admin"
  },
  "csrf_token": "bbbbbbbbbbbbbbbbbbbbbbbbbb",
  "logout_token": "ccccccccccccccccccccccccc"
}

FAILURE:

{
  "message":"Sorry, unrecognized username or password."
}
1
  • 1
    > Go to /admin/config/services/rest and enable User Rest resource. I think you do not need to enable User resource to log in with REST api. Enabling of this resource is only required if you want to perform CRUD operation on User entity. Log in can be achieved with rest api as mentioned by @tyler.frankenstein Feb 8, 2019 at 6:41
3

I use custom RESTFul login on drupal 8 but not with cookie. It's for an mobile app and every time i need information, i use a simple Authenticate :

Since Drupal 8.2x we need 2 files in a module :

rest.ressource.user.rest_ressource.yml in config/install folder

langcode: en
status: true
dependencies:
  module:
    - basic_auth
id: user.rest_ressource
plugin_id: 'user_rest_ressource'
granularity: resource
configuration:
  methods:
    - GET
    - PATCH
  formats:
    - json
  authentication:
    - basic_auth

You can add more method like DELETE / POST

Then we need the file

userRestRessource.php in src/Plugin/rest/resource

    <?php

    namespace Drupal\yourmodule\Plugin\rest\resource;

    use Drupal\Core\Session\AccountProxyInterface;
    use Drupal\rest\Plugin\ResourceBase;
    use Drupal\rest\ResourceResponse;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Psr\Log\LoggerInterface;


    /**
     * Provides a resource to get view modes by entity and bundle.
     *
     * @RestResource(
     *   id = "user_rest_ressource",
     *   label = @Translation("User Rest"),
     *   uri_paths = {
     *     "canonical" = "/api/user/getInfo"
     *   }
     * )
     */
    class UserRestRessource extends ResourceBase {

      /**
       * A current user instance.
       *
       * @var \Drupal\Core\Session\AccountProxyInterface
       */
      protected $currentUser;

      /**
       * Constructs a Drupal\rest\Plugin\ResourceBase object.
       *
       * @param array $configuration
       *   A configuration array containing information about the plugin instance.
       * @param string $plugin_id
       *   The plugin_id for the plugin instance.
       * @param mixed $plugin_definition
       *   The plugin implementation definition.
       * @param array $serializer_formats
       *   The available serialization formats.
       * @param \Psr\Log\LoggerInterface $logger
       *   A logger instance.
       * @param \Drupal\Core\Session\AccountProxyInterface $current_user
       *   A current user instance.
       */
      public function __construct(
        array $configuration,
        $plugin_id,
        $plugin_definition,
        array $serializer_formats,
        LoggerInterface $logger,
        AccountProxyInterface $current_user) {
        parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);

        $this->currentUser = $current_user;

      }

      /**
       * {@inheritdoc}
       */
      public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
        return new static(
          $configuration,
          $plugin_id,
          $plugin_definition,
          $container->getParameter('serializer.formats'),
          $container->get('logger.factory')->get('yourmodulename'),
          $container->get('current_user')
        );
      }

      /**
       * Responds to GET requests.
       *
       * Returns a list of bundles for specified entity.
       *
       * @throws \Symfony\Component\HttpKernel\Exception\HttpException
       *   Throws exception expected.
       */
      public function get() {

          $uid=$this->currentUser->getAccount()->id();
          $role=$this->currentUser->getAccount()->getRoles(1);

//here you can add your custom code
 $responseResource=new ResourceResponse(
          array()

      );
        return $responseResource;
      }

        /**
         * Responds to PATCH requests.
         *
         * Returns a list of bundles for specified entity.
         *
         * @throws \Symfony\Component\HttpKernel\Exception\HttpException
         *   Throws exception expected.
         */
        public function patch(){

        }

    }

Don't forget to go to user right for accept method GET / POST or anything you have add in your config.

With that you can create every custom REST file for every custom entity.

And in my js : Dont forget to call

yoursiteUrl/rest/session/token

for get token

$http({
            method: 'GET',
            url: 'siteUrl/api/user/getInfo?_format=json',
                          withCredentials:true,
                          headers: {
                                   'Content-Type': "application/hal+json",
                                   'X-CSRF-Token': token,
                                   'Authorization': 'Basic ' + btoa(user+':'+password),

                         },


                        }).then(function successCallback(response) {

                             return response;

                          }, function errorCallback(response) {
                              return false;

                          });
2

Following the answer of @tyler.frankenstein, if you wish to implement a login form with Ajax, you can for example use jQuery.

1. Get a CSRF token

We need to make a POST request to the user/login endpoint of the Drupal 8 API. This endpoint (considered as a "non-safe method") requires that you send a CSRF token.

The first step is to get this token by sending an AJAX request to the rest/session/token endpoint:

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

N.B.:

  • The callback parameter is a callback function that will be called when the CSRF token will be fetched
  • We use the Drupal.url function to get the base URL of the site

This token should be send with a X-CSRF-Token header.

2. Login

Consider the following HTML:

<form id="login" method="post" action="" accept-charset="UTF-8">
    <div class="input-field">
        <input id="edit-name" name="name" type="text" class="validate">
        <label for="edit-name">Username or email address</label>
    </div>
    <div class="input-field">
        <input id="edit-pass" name="pass" type="password" class="validate">
        <label for="edit-pass">Password</label>
    </div>
    <p><a href="{{ url('user.pass') }}">Forgot your password?</a></p>
    <button type="submit" class="btn btn-default btn-submit">Sign in</button>
</form>

... and the corresponding jQuery code:

$('form#login').on('submit', function(e) {
    e.preventDefault();

    var inputUsername = $('#edit-name').val();
    var inputPassword = $('#edit-pass').val();

    if (inputUsername != '' && inputPassword != '') {
        getCsrfToken(function(csrfToken) {
            $.ajax({
                url: Drupal.url('user/login?_format=json'),
                type: 'POST',
                dataType: 'json',
                data: JSON.stringify({name: inputUsername, pass: inputPassword}),
                headers: {
                    'X-CSRF-Token': csrfToken
                },
            }).done(function(response) {
                if (response.current_user) {
                    console.log('The user is logged!');
                }
            }).fail(function(jqXHR, textStatus) {
                ...
            });
        });
    }
});

This code has been successfully tested with Drupal 8.3.

I hope this will help you!

0

Yeah sure, I made a blog about how to test it with postman, and also another one about how to configure your drupal site.

In this project I made a login for Drupal with angular, using the Simple OAuth module for the token.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.