diff --git a/admin/tool/oauth2/classes/form/issuer.php b/admin/tool/oauth2/classes/form/issuer.php
index a57b4c21a69..23874bb2042 100644
--- a/admin/tool/oauth2/classes/form/issuer.php
+++ b/admin/tool/oauth2/classes/form/issuer.php
@@ -78,6 +78,10 @@ class issuer extends persistent {
$mform->addRule('clientsecret', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->addHelpButton('clientsecret', 'issuerclientsecret', 'tool_oauth2');
+ // Use basic authentication.
+ $mform->addElement('checkbox', 'basicauth', get_string('usebasicauth', 'tool_oauth2'));
+ $mform->addHelpButton('basicauth', 'usebasicauth', 'tool_oauth2');
+
// Login scopes.
$mform->addElement('text', 'loginscopes', get_string('issuerloginscopes', 'tool_oauth2'));
$mform->addRule('loginscopes', null, 'required', null, 'client');
diff --git a/admin/tool/oauth2/lang/en/tool_oauth2.php b/admin/tool/oauth2/lang/en/tool_oauth2.php
index 8c20c6a4f3f..b8fe75bab7e 100644
--- a/admin/tool/oauth2/lang/en/tool_oauth2.php
+++ b/admin/tool/oauth2/lang/en/tool_oauth2.php
@@ -95,6 +95,8 @@ $string['systemaccountconnected_help'] = 'System accounts are used to provide ad
$string['systemaccountconnected'] = 'System account connected';
$string['systemaccountnotconnected'] = 'System account not connected';
$string['systemauthstatus'] = 'System account connected';
+$string['usebasicauth'] = 'Authenticate token requests via HTTP headers';
+$string['usebasicauth_help'] = 'Utilize the HTTP Basic authentication scheme when sending client ID and password with a refresh token request. Recommended by the OAuth 2 standard, but may not be available with some issuers.';
$string['userfieldexternalfield'] = 'External field name';
$string['userfieldexternalfield_help'] = 'Name of the field provided by the external OAuth system.';
$string['userfieldinternalfield_help'] = 'Name of the Moodle user field that should be mapped from the external field.';
diff --git a/lib/classes/oauth2/client.php b/lib/classes/oauth2/client.php
index 72baad9ae3e..7f3cc96f93d 100644
--- a/lib/classes/oauth2/client.php
+++ b/lib/classes/oauth2/client.php
@@ -70,6 +70,7 @@ class client extends \oauth2_client {
if (empty($returnurl)) {
$returnurl = new moodle_url('/');
}
+ $this->basicauth = $issuer->get('basicauth');
parent::__construct($issuer->get('clientid'), $issuer->get('clientsecret'), $returnurl, $scopes);
}
@@ -177,11 +178,17 @@ class client extends \oauth2_client {
$refreshtoken = $systemaccount->get('refreshtoken');
$params = array('refresh_token' => $refreshtoken,
- 'client_id' => $this->issuer->get('clientid'),
- 'client_secret' => $this->issuer->get('clientsecret'),
'grant_type' => 'refresh_token'
);
+ if ($this->basicauth) {
+ $idsecret = urlencode($this->issuer->get('clientid')) . ':' . urlencode($this->issuer->get('clientsecret'));
+ $this->setHeader('Authorization: Basic ' . base64_encode($idsecret));
+ } else {
+ $params['client_id'] = $this->issuer->get('clientid');
+ $params['client_secret'] = $this->issuer->get('clientsecret');
+ }
+
// Requests can either use http GET or POST.
if ($this->use_http_get()) {
$response = $this->get($this->token_url(), $params);
diff --git a/lib/classes/oauth2/issuer.php b/lib/classes/oauth2/issuer.php
index c6cb7567c9a..8baa221daef 100644
--- a/lib/classes/oauth2/issuer.php
+++ b/lib/classes/oauth2/issuer.php
@@ -72,6 +72,10 @@ class issuer extends persistent {
'type' => PARAM_BOOL,
'default' => false
),
+ 'basicauth' => array(
+ 'type' => PARAM_BOOL,
+ 'default' => false
+ ),
'scopessupported' => array(
'type' => PARAM_RAW,
'null' => NULL_ALLOWED,
diff --git a/lib/db/install.xml b/lib/db/install.xml
index 03e5684d4ad..c1a4efb9607 100644
--- a/lib/db/install.xml
+++ b/lib/db/install.xml
@@ -3514,6 +3514,7 @@
+
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 4024e5a4936..f61a19cface 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -2811,5 +2811,20 @@ function xmldb_main_upgrade($oldversion) {
// Automatically generated Moodle v3.4.0 release upgrade line.
// Put any upgrade step following this.
+ if ($oldversion < 2017111300.011) {
+
+ // Define field basicauth to be added to oauth2_issuer.
+ $table = new xmldb_table('oauth2_issuer');
+ $field = new xmldb_field('basicauth', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'showonloginpage');
+
+ // Conditionally launch add field basicauth.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2017111300.011);
+ }
+
return true;
}
diff --git a/lib/oauthlib.php b/lib/oauthlib.php
index d269cc10935..c933decedbf 100644
--- a/lib/oauthlib.php
+++ b/lib/oauthlib.php
@@ -403,6 +403,8 @@ abstract class oauth2_client extends curl {
private $mocknextresponse = '';
/** @var array $upgradedcodes list of upgraded codes in this request */
private static $upgradedcodes = [];
+ /** @var bool basicauth */
+ protected $basicauth = false;
/**
* Returns the auth url for OAuth 2.0 request
@@ -542,12 +544,18 @@ abstract class oauth2_client extends curl {
public function upgrade_token($code) {
$callbackurl = self::callback_url();
$params = array('code' => $code,
- 'client_id' => $this->clientid,
- 'client_secret' => $this->clientsecret,
'grant_type' => 'authorization_code',
'redirect_uri' => $callbackurl->out(false),
);
+ if ($this->basicauth) {
+ $idsecret = urlencode($this->clientid) . ':' . urlencode($this->clientsecret);
+ $this->setHeader('Authorization: Basic ' . base64_encode($idsecret));
+ } else {
+ $params['client_id'] = $this->clientid;
+ $params['client_secret'] = $this->clientsecret;
+ }
+
// Requests can either use http GET or POST.
if ($this->use_http_get()) {
$response = $this->get($this->token_url(), $params);
diff --git a/version.php b/version.php
index d168eebf4aa..f8eefa9f540 100644
--- a/version.php
+++ b/version.php
@@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
-$version = 2017111300.01; // 20171113 = branching date YYYYMMDD - do not modify!
+$version = 2017111300.011; // 20171113 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.