Commit f166d464 authored by Achilles Katsaros's avatar Achilles Katsaros

add drupal modules files

parent 7f12bb86
Modules extend your site functionality beyond Drupal core.
Placing downloaded and custom modules in this directory separates downloaded and
custom modules from Drupal core's modules. This allows Drupal core to be updated
without overwriting these files.
Contributed modules from the Drupal community may be downloaded at
You may create subdirectories in this directory, to organize your added modules,
without breaking the site. Some common subdirectories include "contrib" for
contributed modules, and "custom" for custom modules. Note that if you move a
module to a subdirectory after it has been enabled, you may need to clear the
Drupal cache so it can be found.
There are number of directories that are ignored when looking for modules. These
are 'src', 'lib', 'vendor', 'assets', 'css', 'files', 'images', 'js', 'misc',
'templates', 'includes', 'fixtures' and 'Drupal'.
In multisite configurations, modules found in this directory are available to
all sites. You may also put modules in the sites/all/modules directory, and the
versions in sites/all/modules will take precedence over versions of the same
module that are here. Alternatively, the sites/your_site_name/modules directory
pattern may be used to restrict modules to a specific site instance.
Refer to the “Developing for Drupal” section of the README.txt in the Drupal
root directory for further information on extending Drupal with custom modules.
consumers @ ef5644c2
Subproject commit ef5644c2a46ccaf527f924b6360f1c366ba876d5
language: php
sudo: false
- 5.6
- 7
fast_finish: true
database: drupal
username: root
encoding: utf8
# Cache composer downloads because cloning Coder form is very slow :-(
- $HOME/.composer
# Remove Xdebug as we don't need it and it causes
# PHP Fatal error: Maximum function nesting level of '256' reached.
# We also don't care if that file exists or not on PHP 7.
- phpenv config-rm xdebug.ini || true
# Remember the current simple_oauth test directory for later use in the Drupal
# installation.
- TESTDIR=$(pwd)
# Navigate out of module directory to prevent blown stack by recursive module
# lookup.
- cd ..
# Create database.
- mysql -e 'create database drupal'
# Export database variable for kernel tests.
- export SIMPLETEST_DB=mysql://root:@
- travis_retry git clone --branch $DRUPAL_CORE --depth 1
- cd drupal
# Reference simple_oauth in build site.
- ln -s $TESTDIR modules/simple_oauth
- travis_retry composer self-update
- travis_retry composer install
# Add dependency manually since installing via git pull is not bringing that.
- travis_retry composer require league/oauth2-server:^5.1
# Start a web server on port 8888, run in the background.
- php -S localhost:8888 &
# Export web server URL for browser tests.
- export SIMPLETEST_BASE_URL=http://localhost:8888
# Install PHPCS to check for Drupal coding standards.
- travis_retry composer global require drupal/coder
- ~/.composer/vendor/bin/phpcs --config-set installed_paths ~/.composer/vendor/drupal/coder/coder_sniffer
# Run the PHPUnit tests which also include the kernel tests.
- ./vendor/bin/phpunit --verbose --color -c ./core/phpunit.xml.dist ./modules/simple_oauth
# Check for coding standards violations
- cd modules/simple_oauth && ~/.composer/vendor/bin/phpcs --standard=DrupalPractice .
This diff is collapsed.
[![Build Status](](
Simple OAuth is an implementation of the [OAuth 2.0 Authorization Framework RFC]( Using OAuth 2.0 Bearer Token is very easy. See how you can get the basics working in **less than 5 minutes**! This project is focused in simplicity of use and flexibility. When deciding which project to use, also consider other projects like [OAuth](, an OAuth 1 implementation that doesn't rely on you having https in your production server.
### Based on League\OAuth2
This module uses the fantastic PHP library [OAuth 2.0 Server]( from [The League of Extraordinary Packages]( This library has become the de-facto standard for modern PHP applications and is thoroughly tested.
[![Latest Version](](
[![Software License](](
[![Build Status](](
[![Coverage Status](](
[![Quality Score](](
[![Total Downloads](](
### Quick demo (Password Grant)
1. Install the module using Composer: `composer require drupal/simple_oauth:8.x-2.x`. You can use any other installation method, as long as you install the [OAuth2 Server]( composer package.
2. Generate a pair of keys to encrypt the tokens. And store them outside of your document root for security reasons.
openssl genrsa -out private.key 2048
openssl rsa -in private.key -pubout > public.key
3. Save the path to your keys in: `/admin/config/people/simple_oauth`.
3. Go to [REST UI]( and enable the _oauth2_ authentication in your resource.
4. Create a Client Application by going to: `/admin/config/services/consumer/add`.
5. Create a token with your credentials by making a `POST` request to `/oauth/token`. See [the documentation]( about what fields your request should contain.
6. (Not shown) Permissions are set to only allow to view nodes via REST with the authenticated user.
7. Request a node via REST without authentication and watch it fail.
8. Request a node via REST with the header `Authorization: Bearer {YOUR_TOKEN}` and watch it succeed.
![Simple OAuth animation](
### Video tutorials
[![](]( Watch a detailed explanation on how to use this module in the video tutorials:
1. [Basic configuration.](
2. [Refresh your tokens.](
3. [Add extra security with resources.](
### My token has expired!
First, that is a good thing. Tokens are like cash, if you have it you can use it. You don't need to prove that token belongs to you, so don't let anyone steal your token. In order to lower the risk tokens should expire fairly quickly. If your token expires in 120s then it will be only usable during that window.
#### What do I do if my token was expired?
Along with your access token, an authentication token is created. It's called the _refresh token_ . It's a longer lived token, that it's associated to an access token and can be used to create a replica of your expired access token. You can then use that new access token normally. To use your refresh token you will need to make use of the [_Refresh Token Grant_]( That will return a JSON document with the new token and a new refresh token. That URL can only be accessed with your refresh token, even if your access token is still valid.
#### What do I do if my refresh token was also expired, or I don't have a refresh token?
Then you will need to generate a new token from scratch. You can avoid this by refreshing your access token before your refresh token expires. This way you avoid the need to require the user to prove their identity to Drupal to create a new token. Another way to mitigate this is to use longer expiration times in your tokens. This will work, but the the recommendation is to refresh your token in time.
### Recommendation
Check the official documentation on the [Bearer Token Usage]( And **turn on SSL!**.
### Issues and contributions
Issues and development happens in the [ issue queue](
"name": "drupal/simple_oauth",
"description": "The Simple OAuth module for Drupal",
"type": "drupal-module",
"require": {
"league/oauth2-server": "~6.0"
"license": "GPL-2.0+",
"authors": [
"name": "Mateu Aguiló Bosch",
"email": ""
langcode: en
status: true
id: access_token
label: 'Access Token'
description: 'The access token type.'
locked: true
langcode: en
status: true
id: auth_code
label: 'Auth code'
description: 'The auth code type.'
locked: true
langcode: en
status: true
id: refresh_token
label: 'Refresh token'
description: 'The refresh token type.'
locked: true
access_token_expiration: 300
refresh_token_expiration: 1209600
type: config_entity
label: 'OAuth2 token type'
type: string
label: 'ID'
type: label
label: 'Label'
type: text
label: 'Description'
type: boolean
label: 'Locked'
type: config_object
label: 'Simple OAuth Settings'
type: integer
label: 'Access Token Expiration Time'
description: 'The default period in seconds while a access token is valid'
type: integer
label: 'Refresh Token Expiration Time'
description: 'The default period in seconds while a refresh token is valid'
type: path
label: 'Public Key'
description: 'The path to the public file.'
type: path
label: 'Private Key'
description: 'The path to the private file.'
name: Simple OAuth
type: module
description: 'The OAuth 2.0 Authorization Framework: Bearer Token Usage'
# core: 8.x
package: Authentication
configure: oauth2_token.settings
- drupal:system (>=8.3)
- serialization
- consumers
# Information added by packaging script on 2017-09-10
version: '8.x-3.0-beta1'
core: '8.x'
project: 'simple_oauth'
datestamp: 1505028252
* @file
* Module installation file.
* Enable the Simple OAuth Consumers module.
function simple_oauth_update_8200() {
route_name: 'entity.consumer.add_form'
title: 'Add Client'
- oauth2_token.settings
title: Simple OAuth
description: 'Configure the Simple OAuth settings and manage entities.'
route_name: oauth2_token.settings
parent: user.admin_index
title: 'Clients'
route_name: entity.consumer.collection
description: 'List Clients'
base_route: oauth2_token.settings
# Access Token routing definition
route_name: oauth2_token.settings
title: 'Settings'
base_route: oauth2_token.settings
route_name: entity.oauth2_token.collection
base_route: oauth2_token.settings
title: 'Tokens'
route_name: entity.oauth2_token.canonical
base_route: entity.oauth2_token.canonical
title: 'View'
route_name: entity.oauth2_token.delete_form
base_route: entity.oauth2_token.canonical
title: Delete
weight: 10
* @file
* Contains simple_oauth.module..
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\consumers\Entity\Consumer;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\user\RoleInterface;
* Implements hook_cron().
function simple_oauth_cron() {
/** @var \Drupal\simple_oauth\ExpiredCollector $collector */
$collector = \Drupal::service('simple_oauth.expired_collector');
// Collect all expired tokens and delete them.
* Implements hook_entity_update().
function simple_oauth_entity_update(EntityInterface $entity) {
/** @var \Drupal\simple_oauth\ExpiredCollector $collector */
$collector = \Drupal::service('simple_oauth.expired_collector');
// Collect the affected tokens and expire them.
if ($entity instanceof AccountInterface) {
if ($entity instanceof Consumer) {
* Implements hook_entity_base_field_info().
function simple_oauth_entity_base_field_info(EntityTypeInterface $entity_type) {
$fields = [];
if ($entity_type->id() == 'consumer') {
$fields['secret'] = BaseFieldDefinition::create('password')
->setLabel(new TranslatableMarkup('Secret'))
->setDescription(new TranslatableMarkup('The secret key of this client (hashed).'));
$fields['confidential'] = BaseFieldDefinition::create('boolean')
->setLabel(new TranslatableMarkup('Is Confidential?'))
->setDescription(new TranslatableMarkup('A boolean indicating whether the client secret needs to be validated or not.'))
->setDisplayOptions('view', [
'label' => 'inline',
'type' => 'boolean',
'weight' => 3,
->setDisplayOptions('form', [
'weight' => 3,
$fields['roles'] = BaseFieldDefinition::create('entity_reference')
->setLabel(new TranslatableMarkup('Scopes'))
->setDescription(new TranslatableMarkup('The roles for this Consumer. OAuth2 scopes are implemented as Drupal roles.'))
->setSetting('target_type', 'user_role')
->setSetting('handler', 'default')
->setDisplayOptions('view', [
'label' => 'inline',
'type' => 'entity_reference_label',
'weight' => 5,
->setDisplayOptions('form', [
'type' => 'options_buttons',
'weight' => 5,
return $fields;
* Implements hook_form_FORM_ID_alter().
function simple_oauth_form_consumer_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
// Add a custom submit behavior.
$form['#entity_builders'][] = 'simple_oauth_form_consumer_form_submit';
$entity_type_manager = \Drupal::service('entity_type.manager');
// Remove automatic roles and administrator roles.
// Get the admin role.
$admin_roles = $entity_type_manager->getStorage('user_role')->getQuery()
->condition('is_admin', TRUE)
$default_value = reset($admin_roles);
$recommendation_text = t(
'Create a <a href=":url">role</a> for every logical group of permissions you want to make available to a consumer.',
[':url' => Url::fromRoute('entity.user_role.collection')->toString()]
$form['roles']['widget']['#description'] .= '<br>' . $recommendation_text;
if (empty($form['roles']['widget']['#options'])) {
drupal_set_message($recommendation_text, 'error');
$form['actions']['#disabled'] = TRUE;
$description = t(
'Use this field to create a hash of the secret key. This module will never store your consumer key, only a hash of it.'
$form['new_secret'] = [
'#type' => 'password',
'#title' => t('New Secret'),
'#description' => $description,
* Extra submit handler.
* @param array $form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The state.
function simple_oauth_form_consumer_form_submit($entity_type_id, Consumer $entity, array &$form, FormStateInterface $form_state) {
if ($entity_type_id !== 'consumer') {
// If the secret was changed, then digest it before saving. If not, then
// leave it alone.
if ($new_secret = $form_state->getValue('new_secret')) {
$entity->get('secret')->value = $new_secret;
* Implements hook_consumers_list_alter().
function simple_oauth_consumers_list_alter(&$data, $context) {
if ($context['type'] === 'header') {
$data['scopes'] = t('Scopes');
else if ($context['type'] === 'row') {
$entity = $context['entity'];
$data['scopes'] = [
'data' => ['#theme' => 'item_list', '#items' => []],
foreach ($entity->get('roles')->getValue() as $role) {
$data['scopes']['data']['#items'][] = $role['target_id'];
add simple_oauth entities:
title: 'Create new Access Token entities'
administer simple_oauth entities:
title: 'Administer Access Token entities'
description: 'Allow to access the administration form to configure Access Token entities.'
delete own simple_oauth entities:
title: 'Delete Access Token entities'
update own simple_oauth entities:
title: 'Edit Access Token entities'
view own simple_oauth entities:
title: 'View Access Token entities'
# Oauth2Token routing definition
path: '/admin/config/people/simple_oauth/oauth2_token/{oauth2_token}'
_entity_view: 'oauth2_token'
_title: 'Access Token'
_entity_access: 'oauth2_token.view'
_admin_route: TRUE
path: '/admin/config/people/simple_oauth/oauth2_token'
_entity_list: 'oauth2_token'
_title: 'Access Token list'
_permission: 'administer simple_oauth entities'
_admin_route: TRUE
base_route: system.admin_content
path: '/admin/config/people/simple_oauth/oauth2_token/{oauth2_token}/delete'
_entity_form: oauth2_token.delete
_title: 'Delete Access Token'
_entity_access: 'oauth2_token.delete'
_admin_route: TRUE
path: '/admin/config/people/simple_oauth'
_form: '\Drupal\simple_oauth\Entity\Form\Oauth2TokenSettingsForm'
_title: 'Simple OAuth Settings'
_permission: 'administer simple_oauth entities'
_admin_route: TRUE
base_route: entity.user.admin_form
path: '/oauth/token'
_controller: 'Drupal\simple_oauth\Controller\Oauth2Token::token'
methods: [POST]
_access: 'TRUE'
class: Drupal\simple_oauth\Authentication\Provider\SimpleOauthAuthenticationProvider
arguments: ['@simple_oauth.server.resource_server', '@entity_type.manager']
- { name: authentication_provider, provider_id: oauth2, global: TRUE, priority: 35 }
class: Drupal\simple_oauth\PageCache\DisallowSimpleOauthRequests
public: false
- { name: page_cache_request_policy }
class: Drupal\simple_oauth\Normalizer\TokenEntityNormalizer
arguments: ['@entity_type.manager']