diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index da459b99..baf35ea4 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -16,23 +16,19 @@ jobs:
lint:
name: "Lint"
runs-on: "ubuntu-latest"
-
strategy:
fail-fast: false
matrix:
- php-version: [ '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1' ]
-
- continue-on-error: ${{ matrix.php-version == '8.1' }}
-
+ php-version: [ '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2' ]
steps:
- uses: "actions/checkout@v2"
- uses: "shivammathur/setup-php@v2"
with:
- php-version: "7.4"
+ php-version: "${{ matrix.php-version }}"
coverage: "none"
ini-values: "memory_limit=-1, zend.assertions=1, error_reporting=-1, display_errors=On"
tools: "composer:v2"
- - uses: "ramsey/composer-install@v1"
+ - uses: "ramsey/composer-install@v2"
- name: "Lint the PHP source code"
run: "./vendor/bin/parallel-lint src test"
@@ -43,47 +39,50 @@ jobs:
- uses: "actions/checkout@v2"
- uses: "shivammathur/setup-php@v2"
with:
- php-version: "7.4"
+ php-version: "latest"
coverage: "none"
ini-values: "memory_limit=-1"
tools: "composer:v2"
- - uses: "ramsey/composer-install@v1"
+ - uses: "ramsey/composer-install@v2"
- name: "Check coding standards"
run: "./vendor/bin/phpcs src --standard=psr2 -sp --colors"
+ coverage:
+ name: "Coverage"
+ runs-on: "ubuntu-latest"
+ steps:
+ - uses: "actions/checkout@v2"
+ - uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: "latest"
+ coverage: "pcov"
+ ini-values: "memory_limit=-1, zend.assertions=1, error_reporting=-1, display_errors=On"
+ tools: "composer"
+ - name: "Prepare for tests"
+ run: "mkdir -p build/logs"
+ - uses: "ramsey/composer-install@v2"
+ - name: "Run unit tests"
+ run: "./vendor/bin/phpunit --colors=always --coverage-clover build/logs/clover.xml --coverage-text"
+ - name: "Publish coverage report to Codecov"
+ uses: "codecov/codecov-action@v2"
+
unit-tests:
name: "Unit Tests"
runs-on: "ubuntu-latest"
- continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
- php-version:
- - "5.6"
- - "7.0"
- - "7.1"
- - "7.2"
- - "7.3"
- - "7.4"
- - "8.0"
- - "8.1"
- experimental:
- - false
-
+ php-version: [ '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2' ]
steps:
- uses: "actions/checkout@v2"
- uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
- coverage: "pcov"
+ coverage: "none"
ini-values: "memory_limit=-1, zend.assertions=1, error_reporting=-1, display_errors=On"
- tools: "composer:v2"
+ tools: "composer"
- name: "Prepare for tests"
run: "mkdir -p build/logs"
- - uses: "ramsey/composer-install@v1"
- with:
- composer-options: "${{ matrix.composer-options }}"
+ - uses: "ramsey/composer-install@v2"
- name: "Run unit tests"
- run: "./vendor/bin/phpunit --colors=always --coverage-clover build/logs/clover.xml"
- - name: "Publish coverage report to Codecov"
- uses: "codecov/codecov-action@v1"
+ run: "./vendor/bin/phpunit --colors=always"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8db2e264..6247164d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# OAuth 2.0 Client Changelog
+## 2.6.1
+
+_Released: 2021-12-22_
+
+* Fix deprecation notices, providing full support for PHP 8.1
+ [#919](https://github.com/thephpleague/oauth2-client/pull/919)
+ [#920](https://github.com/thephpleague/oauth2-client/pull/920)
+
## 2.6.0
_Released: 2020-10-27_
diff --git a/README.md b/README.md
index 96f4b05e..cbb449d4 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ This package provides a base for integrating with [OAuth 2.0](http://oauth.net/2
[![Source Code](https://img.shields.io/badge/source-thephpleague/oauth2--client-blue.svg?style=flat-square)](https://github.com/thephpleague/oauth2-client)
[![Latest Version](https://img.shields.io/github/release/thephpleague/oauth2-client.svg?style=flat-square)](https://github.com/thephpleague/oauth2-client/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/thephpleague/oauth2-client/blob/master/LICENSE)
-[![Build Status](https://img.shields.io/github/workflow/status/thephpleague/oauth2-client/CI?label=CI&logo=github&style=flat-square)](https://github.com/thephpleague/oauth2-client/actions?query=workflow%3ACI)
+[![Build Status](https://img.shields.io/github/actions/workflow/status/thephpleague/oauth2-client/continuous-integration.yml?label=CI&logo=github&style=flat-square)](https://github.com/thephpleague/oauth2-client/actions?query=workflow%3ACI)
[![Codecov Code Coverage](https://img.shields.io/codecov/c/gh/thephpleague/oauth2-client?label=codecov&logo=codecov&style=flat-square)](https://codecov.io/gh/thephpleague/oauth2-client)
[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-client.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-client)
@@ -24,6 +24,7 @@ This package is compliant with [PSR-1][], [PSR-2][], [PSR-4][], and [PSR-7][]. I
We support the following versions of PHP:
+* PHP 8.1
* PHP 8.0
* PHP 7.4
* PHP 7.3
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index 304df935..5cc1c3c5 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -1,23 +1,22 @@
GEM
remote: https://rubygems.org/
specs:
- activesupport (6.0.4.1)
+ activesupport (6.0.6.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
- addressable (2.8.0)
- public_suffix (>= 2.0.2, < 5.0)
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
- commonmarker (0.17.13)
- ruby-enum (~> 0.5)
- concurrent-ruby (1.1.9)
- dnsruby (1.61.7)
+ commonmarker (0.23.9)
+ concurrent-ruby (1.2.2)
+ dnsruby (1.61.9)
simpleidn (~> 0.1)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
@@ -26,38 +25,24 @@ GEM
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.8.1)
- faraday (1.8.0)
- faraday-em_http (~> 1.0)
- faraday-em_synchrony (~> 1.0)
- faraday-excon (~> 1.1)
- faraday-httpclient (~> 1.0.1)
- faraday-net_http (~> 1.0)
- faraday-net_http_persistent (~> 1.1)
- faraday-patron (~> 1.0)
- faraday-rack (~> 1.0)
- multipart-post (>= 1.2, < 3)
+ faraday (2.6.0)
+ faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
- faraday-em_http (1.0.0)
- faraday-em_synchrony (1.0.0)
- faraday-excon (1.1.0)
- faraday-httpclient (1.0.1)
- faraday-net_http (1.0.1)
- faraday-net_http_persistent (1.2.0)
- faraday-patron (1.0.0)
- faraday-rack (1.0.0)
- ffi (1.15.4)
+ faraday-net_http (3.0.1)
+ ffi (1.15.5)
forwardable-extended (2.6.0)
gemoji (3.0.1)
- github-pages (222)
+ github-pages (227)
github-pages-health-check (= 1.17.9)
- jekyll (= 3.9.0)
+ jekyll (= 3.9.2)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
- jekyll-commonmark-ghpages (= 0.1.6)
+ jekyll-commonmark-ghpages (= 0.2.0)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
+ jekyll-include-cache (= 0.2.1)
jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
@@ -66,7 +51,7 @@ GEM
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.3)
jekyll-sass-converter (= 1.5.2)
- jekyll-seo-tag (= 2.7.1)
+ jekyll-seo-tag (= 2.8.0)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.2.0)
@@ -84,12 +69,12 @@ GEM
jekyll-theme-time-machine (= 0.2.0)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.12.0)
- kramdown (= 2.3.1)
+ kramdown (= 2.3.2)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
- nokogiri (>= 1.12.5, < 2.0)
+ nokogiri (>= 1.13.6, < 2.0)
rouge (= 3.26.0)
terminal-table (~> 1.4)
github-pages-health-check (1.17.9)
@@ -98,13 +83,13 @@ GEM
octokit (~> 4.0)
public_suffix (>= 3.0, < 5.0)
typhoeus (~> 1.3)
- html-pipeline (2.14.0)
+ html-pipeline (2.14.3)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.8.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
- jekyll (3.9.0)
+ jekyll (3.9.2)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
@@ -122,12 +107,12 @@ GEM
jekyll-coffeescript (1.1.1)
coffee-script (~> 2.2)
coffee-script-source (~> 1.11.1)
- jekyll-commonmark (1.3.1)
- commonmarker (~> 0.14)
- jekyll (>= 3.7, < 5.0)
- jekyll-commonmark-ghpages (0.1.6)
- commonmarker (~> 0.17.6)
- jekyll-commonmark (~> 1.2)
+ jekyll-commonmark (1.4.0)
+ commonmarker (~> 0.22)
+ jekyll-commonmark-ghpages (0.2.0)
+ commonmarker (~> 0.23.4)
+ jekyll (~> 3.9.0)
+ jekyll-commonmark (~> 1.4.0)
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
@@ -138,6 +123,8 @@ GEM
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
+ jekyll-include-cache (0.2.1)
+ jekyll (>= 3.7, < 5.0)
jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
@@ -157,7 +144,7 @@ GEM
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
- jekyll-seo-tag (2.7.1)
+ jekyll-seo-tag (2.8.0)
jekyll (>= 3.8, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
@@ -210,41 +197,38 @@ GEM
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
- kramdown (2.3.1)
+ kramdown (2.3.2)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
libv8 (3.16.14.19)
liquid (4.0.3)
- listen (3.7.0)
+ listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
- mini_portile2 (2.6.1)
+ mini_portile2 (2.8.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
- minitest (5.14.4)
- multipart-post (2.1.1)
- nokogiri (1.12.5)
- mini_portile2 (~> 2.6.1)
+ minitest (5.18.0)
+ nokogiri (1.14.3)
+ mini_portile2 (~> 2.8.0)
racc (~> 1.4)
- octokit (4.21.0)
- faraday (>= 0.9)
- sawyer (~> 0.8.0, >= 0.5.3)
+ octokit (4.25.1)
+ faraday (>= 1, < 3)
+ sawyer (~> 0.9)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
- public_suffix (4.0.6)
- racc (1.6.0)
- rb-fsevent (0.11.0)
+ public_suffix (4.0.7)
+ racc (1.6.2)
+ rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
ref (2.0.0)
rexml (3.2.5)
rouge (3.26.0)
- ruby-enum (0.9.0)
- i18n
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
safe_yaml (1.0.5)
@@ -253,9 +237,9 @@ GEM
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
- sawyer (0.8.2)
+ sawyer (0.9.2)
addressable (>= 2.3.5)
- faraday (> 0.8, < 2.0)
+ faraday (>= 0.17.3, < 3)
simpleidn (0.2.1)
unf (~> 0.1.4)
terminal-table (1.8.0)
@@ -266,13 +250,13 @@ GEM
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
- tzinfo (1.2.9)
+ tzinfo (1.2.11)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
- unf_ext (0.0.8)
+ unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
- zeitwerk (2.5.1)
+ zeitwerk (2.6.7)
PLATFORMS
ruby
diff --git a/docs/providers/thirdparty.md b/docs/providers/thirdparty.md
index aeabd759..fb0192e7 100755
--- a/docs/providers/thirdparty.md
+++ b/docs/providers/thirdparty.md
@@ -34,6 +34,7 @@ Gateway | Composer Package | Maintainer
[ColorMeShop](https://github.com/pepabo/oauth2-colormeshop) | pepabo/oauth2-colormeshop | [GMO Pepabo, Inc.](https://github.com/pepabo)
[Canvas LMS](https://github.com/smtech/oauth2-canvaslms) | smtech/oauth2-canvaslms | [Seth Battis](https://github.com/battis)
[concrete5](https://github.com/concrete5/oauth2-concrete5) | concrete5/oauth2-concrete5 | [Andrew Embler](https://github.com/aembler)
+[Chaster App](https://github.com/Austomos/oauth2-chaster-app) | austomos/oauth2-chaster-app | [Ben Hyr](https://github.com/Austomos)
[ChatWork](https://github.com/chatwork/oauth2-chatwork-php) | chatwork/oauth2-chatwork | [Yuta Adachi](https://github.com/ada-u)
[Clever](https://github.com/schoolrunner/oauth2-clever) | schoolrunner/oauth2-clever | [Schoolrunner](https://github.com/schoolrunner)
[CloudConvert](https://github.com/osavchenko/oauth2-cloudconvert) | osavchenko/oauth2-cloudconvert | [Oleksandr Savchenko](https://github.com/osavchenko)
@@ -45,6 +46,7 @@ Gateway | Composer Package | Maintainer
[Discord](https://github.com/wohali/oauth2-discord-new) | wohali/oauth2-discord-new | [Joan Touzet](https://github.com/wohali)
[Docusign](https://github.com/AlaaSarhan/oauth2-docusign) | sarhan/oauth2-docusign | [Alaa Sarhan](https://github.com/AlaaSarhan)
[Dokeop](https://github.com/dokeop/oauth2-dokeop) | dokeop/oauth2-dokeop | [Dokeop](https://github.com/dokeop)
+[DonationAlerts](https://github.com/mish-ka-mishka/oauth2-donationalerts) | mkaverin/oauth2-donationalerts | [Michael Kaverin](https://github.com/mish-ka-mishka)
[Dribbble](https://github.com/crewlabs/oauth2-dribbble) | crewlabs/oauth2-dribbble | [Crew Labs](https://crew.co/labs)
[Dropbox](https://github.com/stevenmaguire/oauth2-dropbox) | stevenmaguire/oauth2-dropbox | [Steven Maguire](https://github.com/stevenmaguire)
[Drupal](https://github.com/chrishemmings/oauth2-drupal) | chrishemmings/oauth2-drupal | [Chris Hemmings](https://github.com/chrishemmings)
@@ -54,18 +56,23 @@ Gateway | Composer Package | Maintainer
[Envato](https://github.com/dilab/envato-oauth2-provider) | dilab/envato-oauth2-provider | [Xu Ding](https://github.com/dilab)
[Epic Games](https://github.com/MrPropre/oauth2-epicgames) | mrpropre/oauth2-epicgames | [Adrien Alais](https://github.com/MrPropre)
[ESIA](https://packagist.org/packages/ekapusta/oauth2-esia) | ekapusta/oauth2-esia | [Alexander Ustimenko](https://github.com/ekapusta)
+[Etsy](https://packagist.org/packages/startz/oauth2-etsy) | startz/oauth2-etsy | [Chuck Burgess](https://github.com/cdburgess)
[EVE Online](https://github.com/killmails/oauth2-eve) | killmails/oauth2-eve | [Oizys](https://github.com/syzio)
[Eventbrite](https://github.com/stevenmaguire/oauth2-eventbrite) | stevenmaguire/oauth2-eventbrite | [Steven Maguire](https://github.com/stevenmaguire)
+[FieldEdge](https://github.com/compwright/oauth2-fieldedge) | compwright/oauth2-fieldedge | [Jonathon Hill](https://compwright.com)
+[Firefly III](https://github.com/StanSoftBG/oauth2-firefly-iii) | stansoft/oauth2-firefly-iii | [Stanimir Stoyanov](https://github.com/stratoss)
[Fitbit](https://github.com/djchen/oauth2-fitbit) | djchen/oauth2-fitbit | [Dan Chen](https://github.com/djchen)
[FormAssembly](https://github.com/FatherShawn/oauth2-formassembly) | fathershawn/oauth2-formassembly | [Shawn Duncan](https://github.com/FatherShawn)
[Foursquare](https://github.com/stevenmaguire/oauth2-foursquare) | stevenmaguire/oauth2-foursquare | [Steven Maguire](https://github.com/stevenmaguire)
[FreeAgent](https://github.com/CloudManaged/oauth2-freeagent) | cloudmanaged/oauth2-freeagent | *Unmaintained*
[FreshBooks](https://github.com/zerospam/oauth2-freshbooks) | zerospam/oauth2-freshbooks | [Antoine Aflalo](https://github.com/Belphemur)
+[Genesys](https://github.com/vormkracht10/oauth2-genesys) | vormkracht10/oauth2-genesys | [Vormkracht10](https://github.com/vormkracht10)
[Geocaching](https://github.com/Surfoo/oauth2-geocaching) | surfoo/oauth2-geocaching | [Surfoo](https://github.com/Surfoo)
[GitLab](https://github.com/omines/oauth2-gitlab) | omines/oauth2-gitlab | [Niels Keurentjes](https://github.com/curry684)
[Gumroad](https://github.com/Alofoxx/oauth2-gumroad) | alofoxx/oauth2-gumroad | [Alofoxx](https://github.com/Alofoxx)
[GotoWebinar](https://github.com/dalpras/oauth2-gotowebinar) | dalpras/oauth2-gotowebinar | [Stefano Dal Prà](https://github.com/dalpras)
-[Harvest](https://github.com/nilesuan/oauth2-harvest) | nilesuan/oauth2-harvest | [Nile Suan](https://github.com/nilesuan)
+[Harvest API v2](https://github.com/globalvisionmedia/oauth2-harvest) | globalvisionmedia/oauth2-harvest | [Peter Hawkins](https://www.globalvision.com.au)
+[Harvest API v1](https://github.com/nilesuan/oauth2-harvest) | nilesuan/oauth2-harvest | [Nile Suan](https://github.com/nilesuan)
[HeadHunter](https://packagist.org/packages/alexmasterov/oauth2-headhunter) | alexmasterov/oauth2-headhunter | [Alex Masterov](https://github.com/AlexMasterov)
[Heroku](https://github.com/stevenmaguire/oauth2-heroku) | stevenmaguire/oauth2-heroku | [Steven Maguire](https://github.com/stevenmaguire)
[Housecall Pro](https://github.com/compwright/oauth2-housecallpro) | compwright/oauth2-housecallpro | [Jonathon Hill](https://github.com/compwright)
@@ -74,6 +81,7 @@ Gateway | Composer Package | Maintainer
[Imgur](https://github.com/adam-paterson/oauth2-imgur) | adam-paterson/oauth2-imgur | [Adam Paterson](https://github.com/adam-paterson)
[Jira](https://packagist.org/packages/mrjoops/oauth2-jira) | mrjoops/oauth2-jira | [Alexandre Lahure](https://github.com/mrjoops)
[Keycloak](https://github.com/stevenmaguire/oauth2-keycloak) | stevenmaguire/oauth2-keycloak | [Steven Maguire](https://github.com/stevenmaguire)
+[Lichess](https://packagist.org/packages/joseayram/oauth2-lichess) | joseayram/oauth2-lichess | [José Ayram](https://github.com/joseayram)
[Linode](https://packagist.org/packages/webinarium/oauth2-linode) | webinarium/oauth2-linode | [Artem Rodygin](https://github.com/webinarium)
[Mailchimp](https://github.com/chadhutchins/oauth2-mailchimp) | chadhutchins/oauth2-mailchimp | [Chad Hutchins](https://github.com/chadhutchins)
[Mail.ru](https://packagist.org/packages/aego/oauth2-mailru) | aego/oauth2-mailru | [Alexey](https://github.com/rakeev)
@@ -84,7 +92,9 @@ Gateway | Composer Package | Maintainer
[Meetup](https://packagist.org/packages/wittestier/oauth2-meetup) | wittestier/oauth2-meetup | [WitteStier](https://gitlab.com/WitteStier)
[MercadoLibre](https://github.com/docta/oauth2-mercadolibre) | docta/oauth2-mercadolibre | [Lucas Banegas](https://github.com/lucascono)
[Microsoft](https://github.com/stevenmaguire/oauth2-microsoft) | stevenmaguire/oauth2-microsoft | [Steven Maguire](https://github.com/stevenmaguire)
+[MYOB](https://github.com/globalvisionmedia/oauth2-myob) | globalvisionmedia/oauth2-myob | [Peter Hawkins](https://www.globalvision.com.au)
[Mollie](https://github.com/mollie/oauth2-mollie-php) | mollie/oauth2-mollie-php | [Mollie](https://github.com/mollie)
+[Monizze](https://github.com/jzecca/oauth2-monizze) | jzecca/oauth2-monizze | [Jérôme Zecca](https://github.com/jzecca)
[Mixer](https://gitlab.com/morgann/oauth2-mixer) | morgann/oauth2-mixer | [Morgann](https://gitlab.com/morgann/oauth2-mixer)
[Naver](https://packagist.org/packages/deminoth/oauth2-naver) | deminoth/oauth2-naver | [SangYeob Bono Yu](https://github.com/deminoth)
[Netatmo](https://github.com/rugaard/oauth2-netatmo) | rugaard/oauth2-netatmo | [Morten Rugaard](https://github.com/rugaard)
@@ -106,9 +116,13 @@ Gateway | Composer Package | Maintainer
[Resource Guru](https://github.com/adam-paterson/oauth2-resource-guru) | adam-paterson/oauth2-resource-guru | [Adam Paterson](https://github.com/adam-paterson)
[Riot (RSO)](https://github.com/kdefives/oauth2-riot) | kdefives/oauth2-riot | [Kevin Defives](https://github.com/kdefives)
[Salesforce](https://github.com/stevenmaguire/oauth2-salesforce) | stevenmaguire/oauth2-salesforce | [Steven Maguire](https://github.com/stevenmaguire)
+[SceneId](https://github.com/potibm/oauth2-sceneid) | potibm/oauth2-sceneid | [Stefan Keßeler](https://github.com/potibm)
+[Service Fusion](https://github.com/compwright/oauth2-servicefusion) | compwright/oauth2-servicefusion | [Jonathon Hill](https://compwright.com)
+[ServiceTitan](https://github.com/compwright/oauth2-servicetitan) | compwright/oauth2-servicetitan | [Jonathon Hill](https://compwright.com)
[Shopify](https://github.com/multidimension-al/oauth2-shopify) | multidimensional/oauth2-shopify | [multidimension.al](https://multidimension.al/)
[Slack](https://github.com/adam-paterson/oauth2-slack) | adam-paterson/oauth2-slack | [Adam Paterson](https://github.com/adam-paterson)
[Snapchat](https://github.com/pbringetto/oauth2-snapchat) | pbringetto/oauth2-snapchat | [Paul Bringetto](https://github.com/pbringetto)
+[SoundCloud](https://packagist.org/packages/martin1982/oauth2-soundcloud) | martin1982/oauth2-soundcloud | [Martin de Keijzer](https://github.com/martin1982)
[Spotify](https://packagist.org/packages/audeio/spotify-web-api) | audeio/spotify-web-api | [Jonjo McKay](https://github.com/jonjomckay)
[Spotify](https://packagist.org/packages/kerox/oauth2-spotify) | kerox/oauth2-spotify | [Romain Monteil](https://github.com/ker0x)
[SteemConnect V2](https://github.com/hernandev/oauth2-sc2) | hernandev/oauth2-sc2 | [Diego Hernandes](https://github.com/hernandev)
@@ -117,13 +131,16 @@ Gateway | Composer Package | Maintainer
[Square](https://packagist.org/packages/wheniwork/oauth2-square) | wheniwork/oauth2-square | [Woody Gilk](https://github.com/shadowhand)
[StackExchange](https://packagist.org/packages/alexmasterov/oauth2-stackexchange) | alexmasterov/oauth2-stackexchange | [Alex Masterov](https://github.com/AlexMasterov)
[SuperJob](https://packagist.org/packages/alexmasterov/oauth2-superjob) | alexmasterov/oauth2-superjob | [Alex Masterov](https://github.com/AlexMasterov)
+[TikTok](https://github.com/bastiaandewaele/oauth2-tiktok) | bastiaandewaele/oauth2-tiktok | [Bastiaan Dewaele](https://github.com/bastiaandewaele)
[Thingiverse](https://packagist.org/packages/freshworkx/oauth2-thingiverse) | freshworkx/oauth2-thingiverse | [Jens Neumann](https://github.com/freshworkx)
[ThirtySevenSignals](https://github.com/nilesuan/oauth2-thirtysevensignals) | nilesuan/oauth2-thirtysevensignals | [Nile Suan](https://github.com/nilesuan)
[Trakt.tv](https://github.com/Bogstag/oauth2-trakt) | bogstag/oauth2-trakt | [Krister Bogstag](https://github.com/Bogstag/)
[Trovo](https://github.com/artandor/oauth2-trovo) | artandor/oauth2-trovo | [Nicolas Mylle](https://github.com/artandor/)
+[Trustpilot](https://github.com/dmt-software/oauth2-trustpilot) | dmt-software/oauth2-trustpilot | [DMT software](https://github.com/dmt-software/)
[Twinfield](https://github.com/php-twinfield/twinfield) | php-twinfield/twinfield | [Mollie B.V.](https://github.com/mollie)
[Twitch.tv](https://github.com/tpavlek/oauth2-twitch) | depotwarehouse/oauth2-twitch | [Troy Pavlek](https://github.com/tpavlek)
[Twitch.tv (New API Helix)](https://github.com/vertisan/oauth2-twitch-helix) | vertisan/oauth2-twitch-helix | [Paweł Farys](https://github.com/vertisan)
+[Twitter](https://github.com/smolblog/oauth2-twitter) | smolblog/oauth2-twitter | [Evan Hildreth](https://github.com/oddevan)
[Uber](https://github.com/stevenmaguire/oauth2-uber) | stevenmaguire/oauth2-uber | [Steven Maguire](https://github.com/stevenmaguire)
[Unsplash](https://github.com/hughbertd/oauth2-unsplash) | hughbertd/oauth2-unsplash | [Hugh Downer](https://github.com/hughbertd)
[Untappd](https://github.com/shadowhand/oauth2-untappd) | shadowhand/oauth2-untappd | [Woody Gilk](https://github.com/shadowhand)
@@ -132,6 +149,7 @@ Gateway | Composer Package | Maintainer
[Vkontakte](https://github.com/j4k/oauth2-vkontakte) | j4k/oauth2-vkontakte | [Jack W](https://github.com/j4k)
[Withings](https://github.com/waytohealth/oauth2-withings) | waytohealth/oauth2-withings | [Way to Health](https://github.com/waytohealth)
[WordPress](https://github.com/krombox/oauth2-wordpress) | krombox/oauth2-wordpress | [Roman Kapustian](https://github.com/krombox)
+[Webflow](https://github.com/koalatiapp/oauth2-webflow) | koalati/oauth2-webflow | [Koalati](https://github.com/koalatiapp)
[Wechat](https://github.com/oakhope/oauth2-wechat) | oakhope/oauth2-wechat | [Benji Wang](https://github.com/oakhope)
[WeCounsel](https://github.com/stevenmaguire/oauth2-wecounsel) | stevenmaguire/oauth2-wecounsel | [Steven Maguire](https://github.com/stevenmaguire)
[Wrike](https://github.com/michaelKaefer/oauth2-wrike) | michaelkaefer/oauth2-wrike | [Michael Käfer](https://github.com/michaelKaefer)
diff --git a/docs/usage.md b/docs/usage.md
index 5950fd95..88a8c21f 100755
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -16,6 +16,7 @@ The following example uses the out-of-the-box `GenericProvider` provided by this
The *authorization code* grant type is the most common grant type used when authenticating users with a third-party service. This grant type utilizes a *client* (this library), a *service provider* (the server), and a *resource owner* (the account with credentials to a protected—or owned—resource) to request access to resources owned by the user. This is often referred to as _3-legged OAuth_, since there are three parties involved.
+
```php
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => 'XXXXXX', // The client ID assigned to you by the provider
@@ -37,12 +38,16 @@ if (!isset($_GET['code'])) {
// Get the state generated for you and store it to the session.
$_SESSION['oauth2state'] = $provider->getState();
+ // Optional, only required when PKCE is enabled.
+ // Get the PKCE code generated for you and store it to the session.
+ $_SESSION['oauth2pkceCode'] = $provider->getPkceCode();
+
// Redirect the user to the authorization URL.
header('Location: ' . $authorizationUrl);
exit;
// Check given state against previously stored one to mitigate CSRF attack
-} elseif (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) {
+} elseif (empty($_GET['state']) || empty($_SESSION['oauth2state']) || $_GET['state'] !== $_SESSION['oauth2state']) {
if (isset($_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
@@ -53,6 +58,10 @@ if (!isset($_GET['code'])) {
} else {
try {
+
+ // Optional, only required when PKCE is enabled.
+ // Restore the PKCE code stored in the session.
+ $provider->setPkceCode($_SESSION['oauth2pkceCode']);
// Try to get an access token using the authorization code grant.
$accessToken = $provider->getAccessToken('authorization_code', [
@@ -90,6 +99,31 @@ if (!isset($_GET['code'])) {
}
```
+### Authorization Code Grant with PKCE
+
+To enable PKCE (Proof Key for Code Exchange) you can set the `pkceMethod` option for the provider.
+Supported methods are:
+- `S256` Recommended method. The code challenge will be hashed with sha256.
+- `plain` **NOT** recommended. The code challenge will be sent as plain text. Only use this if no other option is possible.
+
+You can configure the PKCE method as follows:
+```php
+$provider = new \League\OAuth2\Client\Provider\GenericProvider([
+ // ...
+ // other options
+ // ...
+ 'pkceMethod' => \League\OAuth2\Client\Provider\GenericProvider::PKCE_METHOD_S256
+]);
+```
+The PKCE code needs to be used between requests and therefore be saved and restored, usually via the session.
+In the [example](#authorization-code-grant-example) above this is done as follows:
+```php
+// Store the PKCE code after the `getAuthorizationUrl()` call.
+$_SESSION['oauth2pkceCode'] = $provider->getPkceCode();
+// ...
+// Restore the PKCE code before the `getAccessToken()` call.
+$provider->setPkceCode($_SESSION['oauth2pkceCode']);
+```
Refreshing a Token
------------------
diff --git a/src/Provider/AbstractProvider.php b/src/Provider/AbstractProvider.php
index d1679998..293a54d6 100644
--- a/src/Provider/AbstractProvider.php
+++ b/src/Provider/AbstractProvider.php
@@ -17,6 +17,7 @@
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\ClientInterface as HttpClientInterface;
use GuzzleHttp\Exception\BadResponseException;
+use InvalidArgumentException;
use League\OAuth2\Client\Grant\AbstractGrant;
use League\OAuth2\Client\Grant\GrantFactory;
use League\OAuth2\Client\OptionProvider\OptionProviderInterface;
@@ -44,7 +45,7 @@ abstract class AbstractProvider
use QueryBuilderTrait;
/**
- * @var string Key used in a token response to identify the resource owner.
+ * @var string|null Key used in a token response to identify the resource owner.
*/
const ACCESS_TOKEN_RESOURCE_OWNER_ID = null;
@@ -58,6 +59,19 @@ abstract class AbstractProvider
*/
const METHOD_POST = 'POST';
+ /**
+ * @var string PKCE method used to fetch authorization token.
+ * The PKCE code challenge will be hashed with sha256 (recommended).
+ */
+ const PKCE_METHOD_S256 = 'S256';
+
+ /**
+ * @var string PKCE method used to fetch authorization token.
+ * The PKCE code challenge will be sent as plain text, this is NOT recommended.
+ * Only use `plain` if no other option is possible.
+ */
+ const PKCE_METHOD_PLAIN = 'plain';
+
/**
* @var string
*/
@@ -78,6 +92,11 @@ abstract class AbstractProvider
*/
protected $state;
+ /**
+ * @var string|null
+ */
+ protected $pkceCode = null;
+
/**
* @var GrantFactory
*/
@@ -264,6 +283,32 @@ public function getState()
return $this->state;
}
+ /**
+ * Set the value of the pkceCode parameter.
+ *
+ * When using PKCE this should be set before requesting an access token.
+ *
+ * @param string $pkceCode
+ * @return self
+ */
+ public function setPkceCode($pkceCode)
+ {
+ $this->pkceCode = $pkceCode;
+ return $this;
+ }
+
+ /**
+ * Returns the current value of the pkceCode parameter.
+ *
+ * This can be accessed by the redirect handler during authorization.
+ *
+ * @return string|null
+ */
+ public function getPkceCode()
+ {
+ return $this->pkceCode;
+ }
+
/**
* Returns the base URL for authorizing a client.
*
@@ -305,6 +350,27 @@ protected function getRandomState($length = 32)
return bin2hex(random_bytes($length / 2));
}
+ /**
+ * Returns a new random string to use as PKCE code_verifier and
+ * hashed as code_challenge parameters in an authorization flow.
+ * Must be between 43 and 128 characters long.
+ *
+ * @param int $length Length of the random string to be generated.
+ * @return string
+ */
+ protected function getRandomPkceCode($length = 64)
+ {
+ return substr(
+ strtr(
+ base64_encode(random_bytes($length)),
+ '+/',
+ '-_'
+ ),
+ 0,
+ $length
+ );
+ }
+
/**
* Returns the default scopes used by this provider.
*
@@ -326,6 +392,14 @@ protected function getScopeSeparator()
return ',';
}
+ /**
+ * @return string|null
+ */
+ protected function getPkceMethod()
+ {
+ return null;
+ }
+
/**
* Returns authorization parameters based on provided options.
*
@@ -355,6 +429,26 @@ protected function getAuthorizationParameters(array $options)
// Store the state as it may need to be accessed later on.
$this->state = $options['state'];
+ $pkceMethod = $this->getPkceMethod();
+ if (!empty($pkceMethod)) {
+ $this->pkceCode = $this->getRandomPkceCode();
+ if ($pkceMethod === static::PKCE_METHOD_S256) {
+ $options['code_challenge'] = trim(
+ strtr(
+ base64_encode(hash('sha256', $this->pkceCode, true)),
+ '+/',
+ '-_'
+ ),
+ '='
+ );
+ } elseif ($pkceMethod === static::PKCE_METHOD_PLAIN) {
+ $options['code_challenge'] = $this->pkceCode;
+ } else {
+ throw new InvalidArgumentException('Unknown PKCE method "' . $pkceMethod . '".');
+ }
+ $options['code_challenge_method'] = $pkceMethod;
+ }
+
// Business code layer might set a different redirect_uri parameter
// depending on the context, leave it as-is
if (!isset($options['redirect_uri'])) {
@@ -517,8 +611,8 @@ protected function getAccessTokenRequest(array $params)
/**
* Requests an access token using a specified grant and option set.
*
- * @param mixed $grant
- * @param array $options
+ * @param mixed $grant
+ * @param array $options
* @throws IdentityProviderException
* @return AccessTokenInterface
*/
@@ -532,6 +626,10 @@ public function getAccessToken($grant, array $options = [])
'redirect_uri' => $this->redirectUri,
];
+ if (!empty($this->pkceCode)) {
+ $params['code_verifier'] = $this->pkceCode;
+ }
+
$params = $grant->prepareRequestParameters($params, $options);
$request = $this->getAccessTokenRequest($params);
$response = $this->getParsedResponse($request);
@@ -564,7 +662,7 @@ public function getRequest($method, $url, array $options = [])
*
* @param string $method
* @param string $url
- * @param AccessTokenInterface|string $token
+ * @param AccessTokenInterface|string|null $token
* @param array $options Any of "headers", "body", and "protocolVersion".
* @return RequestInterface
*/
diff --git a/src/Provider/Exception/IdentityProviderException.php b/src/Provider/Exception/IdentityProviderException.php
index 52b7e035..55cb438f 100644
--- a/src/Provider/Exception/IdentityProviderException.php
+++ b/src/Provider/Exception/IdentityProviderException.php
@@ -27,7 +27,7 @@ class IdentityProviderException extends \Exception
/**
* @param string $message
* @param int $code
- * @param array|string $response The response body
+ * @param mixed $response The response body
*/
public function __construct($message, $code, $response)
{
@@ -39,7 +39,7 @@ public function __construct($message, $code, $response)
/**
* Returns the exception's response body.
*
- * @return array|string
+ * @return mixed
*/
public function getResponseBody()
{
diff --git a/src/Provider/GenericProvider.php b/src/Provider/GenericProvider.php
index 74393ffd..0fc95f25 100644
--- a/src/Provider/GenericProvider.php
+++ b/src/Provider/GenericProvider.php
@@ -78,6 +78,11 @@ class GenericProvider extends AbstractProvider
*/
private $responseResourceOwnerId = 'id';
+ /**
+ * @var string|null
+ */
+ private $pkceMethod = null;
+
/**
* @param array $options
* @param array $collaborators
@@ -114,6 +119,7 @@ protected function getConfigurableOptions()
'responseCode',
'responseResourceOwnerId',
'scopes',
+ 'pkceMethod',
]);
}
@@ -205,6 +211,14 @@ protected function getScopeSeparator()
return $this->scopeSeparator ?: parent::getScopeSeparator();
}
+ /**
+ * @inheritdoc
+ */
+ protected function getPkceMethod()
+ {
+ return $this->pkceMethod ?: parent::getPkceMethod();
+ }
+
/**
* @inheritdoc
*/
diff --git a/test/src/Provider/AbstractProviderTest.php b/test/src/Provider/AbstractProviderTest.php
index bf24ba38..b9ebf6f1 100644
--- a/test/src/Provider/AbstractProviderTest.php
+++ b/test/src/Provider/AbstractProviderTest.php
@@ -332,6 +332,122 @@ public function testAuthorizationStateIsRandom()
}
}
+ public function testSetGetPkceCode()
+ {
+ $pkceCode = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
+
+ $provider = $this->getMockProvider();
+ $this->assertEquals($provider, $provider->setPkceCode($pkceCode));
+ $this->assertEquals($pkceCode, $provider->getPkceCode());
+ }
+
+ /**
+ * @dataProvider pkceMethodProvider
+ */
+ public function testPkceMethod($pkceMethod, $pkceCode, $expectedChallenge)
+ {
+ $provider = $this->getMockProvider();
+ $provider->setPkceMethod($pkceMethod);
+ $provider->setFixedPkceCode($pkceCode);
+
+ $url = $provider->getAuthorizationUrl();
+ $this->assertSame($pkceCode, $provider->getPkceCode());
+
+ parse_str(parse_url($url, PHP_URL_QUERY), $qs);
+ $this->assertArrayHasKey('code_challenge', $qs);
+ $this->assertArrayHasKey('code_challenge_method', $qs);
+ $this->assertSame($pkceMethod, $qs['code_challenge_method']);
+ $this->assertSame($expectedChallenge, $qs['code_challenge']);
+
+ // Simulate re-initialization of provider after authorization request
+ $provider = $this->getMockProvider();
+
+ $raw_response = ['access_token' => 'okay', 'expires' => time() + 3600, 'resource_owner_id' => 3];
+ $stream = Mockery::mock(StreamInterface::class);
+ $stream
+ ->shouldReceive('__toString')
+ ->once()
+ ->andReturn(json_encode($raw_response));
+
+ $response = Mockery::mock(ResponseInterface::class);
+ $response
+ ->shouldReceive('getBody')
+ ->once()
+ ->andReturn($stream);
+ $response
+ ->shouldReceive('getHeader')
+ ->once()
+ ->with('content-type')
+ ->andReturn('application/json');
+
+ $client = Mockery::spy(ClientInterface::class, [
+ 'send' => $response,
+ ]);
+ $provider->setHttpClient($client);
+
+ // restore $pkceCode (normally done by client from session)
+ $provider->setPkceCode($pkceCode);
+
+ $provider->getAccessToken('authorization_code', ['code' => 'mock_authorization_code']);
+
+ $client
+ ->shouldHaveReceived('send')
+ ->once()
+ ->withArgs(function ($request) use ($pkceCode) {
+ parse_str((string)$request->getBody(), $body);
+ return $body['code_verifier'] === $pkceCode;
+ });
+ }
+
+ public function pkceMethodProvider()
+ {
+ return [
+ [
+ AbstractProvider::PKCE_METHOD_S256,
+ '1234567890123456789012345678901234567890',
+ 'pOvdVBRUuEzGcMnx9VCLr2f_0_5ZuIMmeAh4H5kqCx0',
+ ],
+ [
+ AbstractProvider::PKCE_METHOD_PLAIN,
+ '1234567890123456789012345678901234567890',
+ '1234567890123456789012345678901234567890',
+ ],
+ ];
+ }
+
+ public function testInvalidPkceMethod()
+ {
+ $provider = $this->getMockProvider();
+ $provider->setPkceMethod('non-existing');
+
+ $this->expectExceptionMessage('Unknown PKCE method "non-existing".');
+ $provider->getAuthorizationUrl();
+ }
+
+ public function testPkceCodeIsRandom()
+ {
+ $last = null;
+ $provider = $this->getMockProvider();
+ $provider->setPkceMethod('S256');
+
+ for ($i = 0; $i < 100; $i++) {
+ // Repeat the test multiple times to verify code_challenge changes
+ $url = $provider->getAuthorizationUrl();
+
+ parse_str(parse_url($url, PHP_URL_QUERY), $qs);
+ $this->assertTrue(1 === preg_match('/^[a-zA-Z0-9-_]{43}$/', $qs['code_challenge']));
+ $this->assertNotSame($qs['code_challenge'], $last);
+ $last = $qs['code_challenge'];
+ }
+ }
+
+ public function testPkceMethodIsDisabledByDefault()
+ {
+ $provider = $this->getAbstractProviderMock();
+ $pkceMethod = $provider->getPkceMethod();
+ $this->assertNull($pkceMethod);
+ }
+
public function testErrorResponsesCanBeCustomizedAtTheProvider()
{
$provider = new MockProvider([
diff --git a/test/src/Provider/Fake.php b/test/src/Provider/Fake.php
index b0bedcbf..7a02b51a 100644
--- a/test/src/Provider/Fake.php
+++ b/test/src/Provider/Fake.php
@@ -14,6 +14,10 @@ class Fake extends AbstractProvider
private $accessTokenMethod = 'POST';
+ private $pkceMethod = null;
+
+ private $fixedPkceCode = null;
+
public function getClientId()
{
return $this->clientId;
@@ -59,6 +63,26 @@ public function getAccessTokenMethod()
return $this->accessTokenMethod;
}
+ public function setPkceMethod($method)
+ {
+ $this->pkceMethod = $method;
+ }
+
+ public function getPkceMethod()
+ {
+ return $this->pkceMethod;
+ }
+
+ public function setFixedPkceCode($code)
+ {
+ return $this->fixedPkceCode = $code;
+ }
+
+ protected function getRandomPkceCode($length = 64)
+ {
+ return $this->fixedPkceCode ?: parent::getRandomPkceCode($length);
+ }
+
protected function createResourceOwner(array $response, AccessToken $token)
{
return new Fake\User($response);
diff --git a/test/src/Provider/GenericProviderTest.php b/test/src/Provider/GenericProviderTest.php
index ae3214f3..65fe93ca 100644
--- a/test/src/Provider/GenericProviderTest.php
+++ b/test/src/Provider/GenericProviderTest.php
@@ -55,6 +55,7 @@ public function testConfigurableOptions()
'responseCode' => 'mock_code',
'responseResourceOwnerId' => 'mock_response_uid',
'scopes' => ['mock', 'scopes'],
+ 'pkceMethod' => 'S256',
];
$provider = new GenericProvider($options + [
@@ -88,6 +89,10 @@ public function testConfigurableOptions()
$getScopeSeparator = $reflection->getMethod('getScopeSeparator');
$getScopeSeparator->setAccessible(true);
$this->assertEquals($options['scopeSeparator'], $getScopeSeparator->invoke($provider));
+
+ $getPkceMethod = $reflection->getMethod('getPkceMethod');
+ $getPkceMethod->setAccessible(true);
+ $this->assertEquals($options['pkceMethod'], $getPkceMethod->invoke($provider));
}
public function testResourceOwnerDetails()
diff --git a/test/src/Tool/ProviderRedirectTraitTest.php b/test/src/Tool/ProviderRedirectTraitTest.php
index e761cd9b..dc06f45a 100644
--- a/test/src/Tool/ProviderRedirectTraitTest.php
+++ b/test/src/Tool/ProviderRedirectTraitTest.php
@@ -15,6 +15,11 @@ class ProviderRedirectTraitTest extends TestCase
{
use ProviderRedirectTrait;
+ /**
+ * @var ClientInterface
+ */
+ private $httpClient;
+
public function getHttpClient()
{
return $this->httpClient;