1

We are working on developing a mobile app and users should be able to log in to the app and in our backend Drupal site authenticated from Keycloak. Our main goal is that the user would be able to login from the app to update/create content using REST api.

We will be using a JWT token generated from Keycloak to authenticate user in the backend site.

We are using the following Drupal core and module versions:

  • Drupal: 8.5.3
  • OAuth2 JWT SSO: 8.x-1.0-rc1
  • OpenID Connect: 8.x-1.0-beta5
  • RESTful Web Services: 8.5.3
  • Simple OAuth: 8.x-3.0
  • OpenID Connect REST API: 8.x-1.0-rc1

I will first try with REST API to see if the implementation will work before integrating it to our mobile app.

Below are the steps of REST request executed in POSTMAN tool

Pre-setup

From http://192.168.254.107:8080/admin/config/services/openid-connect We enable generic and fill in the following fields

GENERIC
Redirect URL: https://192.168.254.107/openid-connect/rest/generic
Client ID: opensocial
Client secret: XXXXX-XXXXX-XXXXX
Authorization endpoint
http://192.168.254.107:8083/auth/realms/master/protocol/openid-connect/auth
Token endpoint
http://192.168.254.107:8083/auth/realms/master/protocol/openid-connect/token
UserInfo endpoint
http://192.168.254.107:8083/auth/realms/master/protocol/openid-connect/userinfo

And I have client created in Keycloak,

http://192.168.254.107:8083/auth/admin/master/console/#/realms/master/clients/XXXXX-XXXXX-XXXXX
Client ID: opensocial
Client Protocol: openid-connect
Access Type: Confidential
* Valid Redirect URIs : http://192.168.254.107:8080/*
Base URL: http://192.168.254.107:8080
Web Origins: http://192.168.254.107:8080/*

Steps

  1. Generate JWT from Keycloak

    REQUEST: POST
    ENDPOINT: http://192.168.254.107:8083/auth/realms/master/protocol/openid-connect/token
    HEADER: Content-Type: application/x-www-form-urlencoded
    BODY: client_id=opensocial&client_secret=f3e8f92d-c9ff-4139-b715-33e3aaa7194d&username=[username_from_keycloak]&password=[password_from_keycloak]&grant_type=password
    
    RESPONSE:
    
        {
            "access_token": "XXXXX.XXXXX.XXXXX",
            "expires_in": 3600,
            "refresh_expires_in": 1800,
            "refresh_token": "XXXXX.XXXXX.XXXXX",
            "token_type": "bearer",
            "not-before-policy": 0,
            "session_state": "7f739b98-421c-4aaf-a85c-6e38424d9492",
            "scope": "email profile"
        }
    
  2. Validated in jwt.io website and/or by fetching userinfo from Keycloak

    REQUEST: GET
    ENDPOINT: http://192.168.254.107:8083/auth/realms/master/protocol/openid-connect/userinfo
    HEADER: Authorization: Bearer [access_token]
    RESPONSE:
    
    {
        "sub": "331e758e-b7cd-44b0-93ca-97aa44310335",
        "email_verified": false,
        "preferred_username": "admin"
    }
    
    1. Create content using token

      REQUEST: POST ENDPOINT: http://192.168.254.107:8080/node (this is the backend site) HEADERS: Content-Type: application/json Authorization: Bearer [access_token] RESPONSE:

      Status: 500 500 Service unavailable (with message) The website encountered an unexpected error. Please try again later.

In Drupal logs I find the following.

Type php

Date Thursday, May 9, 2019 - 06:52 User Anonymous (not verified) Location http://192.168.254.107:8080/node Referrer
Message Error: Call to a member function validateAuthenticatedRequest() on null in Drupal\simple_oauth\Server\ResourceServer->validateAuthenticatedRequest() (line 63 of /opt/app-root/src/html/modules/simple_oauth/src/Server/ResourceServer.php) #0 /opt/app-root/src/html/modules/simple_oauth/src/Authentication/Provider/SimpleOauthAuthenticationProvider.php(63): Drupal\simple_oauth\Server\ResourceServer->validateAuthenticatedRequest(Object(Symfony\Component\HttpFoundation\Request)) #1 /opt/app-root/src/html/core/lib/Drupal/Core/Authentication/AuthenticationManager.php(52): Drupal\simple_oauth\Authentication\Provider\SimpleOauthAuthenticationProvider->authenticate(Object(Symfony\Component\HttpFoundation\Request)) #2 /opt/app-root/src/html/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php(78): Drupal\Core\Authentication\AuthenticationManager->authenticate(Object(Symfony\Component\HttpFoundation\Request)) #3 [internal function]: Drupal\Core\EventSubscriber\AuthenticationSubscriber->onKernelRequestAuthenticate(Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #4 /opt/app-root/src/html/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func(Array, Object(Symfony\Component\HttpKernel\Event\GetResponseEvent), 'kernel.request', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #5 /opt/app-root/src/vendor/symfony/http-kernel/HttpKernel.php(127): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.request', Object(Symfony\Component\HttpKernel\Event\GetResponseEvent)) #6 /opt/app-root/src/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) #7 /opt/app-root/src/html/modules/simple_oauth/src/HttpMiddleware/BasicAuthSwap.php(67): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #8 /opt/app-root/src/html/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #9 /opt/app-root/src/html/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #10 /opt/app-root/src/html/modules/jsonapi/src/StackMiddleware/FormatSetter.php(40): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #11 /opt/app-root/src/html/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\jsonapi\StackMiddleware\FormatSetter->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #12 /opt/app-root/src/html/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #13 /opt/app-root/src/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #14 /opt/app-root/src/html/core/lib/Drupal/Core/DrupalKernel.php(664): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #15 /opt/app-root/src/html/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request)) #16 {main}. Severity Error Hostname 192.168.254.107

Why does using a valid JWT token generated from Keycloak resulted into user not being authenticated in Drupal using REST API request? Is the method I used not possible? If not, then is there any other processes I can follow to achieve the goal?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.