diff --git a/Gemfile b/Gemfile
index b9ca625a6908572c2b464c40838a49ecaeb997f7..a943800f584601d85eacbf46c6ea4b6c6a047e36 100644
--- a/Gemfile
+++ b/Gemfile
@@ -89,8 +89,10 @@ gem 'coverband', '6.1.4', require: false, feature_category: :shared
 gem 'devise', '~> 4.9.3', feature_category: :system_access
 gem 'devise-pbkdf2-encryptable', '~> 0.0.0', path: 'vendor/gems/devise-pbkdf2-encryptable' # rubocop:todo Gemfile/MissingFeatureCategory
 gem 'bcrypt', '~> 3.1', '>= 3.1.14' # rubocop:todo Gemfile/MissingFeatureCategory
-gem 'doorkeeper', '~> 5.6', '>= 5.6.6' # rubocop:todo Gemfile/MissingFeatureCategory
-gem 'doorkeeper-openid_connect', '~> 1.8', '>= 1.8.7' # rubocop:todo Gemfile/MissingFeatureCategory
+gem 'doorkeeper', '~> 5.8', '>= 5.8.0', feature_category: :system_access
+gem 'doorkeeper-openid_connect', '~> 1.8',
+  path: 'vendor/gems/doorkeeper-openid_connect', # See Gem README for why this is vendored
+  feature_category: :system_access
 gem 'doorkeeper-device_authorization_grant', '~> 1.0.0', feature_category: :system_access
 gem 'rexml', '~> 3.3.2' # rubocop:todo Gemfile/MissingFeatureCategory
 gem 'ruby-saml', '~> 1.17.0', feature_category: :system_access
diff --git a/Gemfile.checksum b/Gemfile.checksum
index d2ab6768fa3092c6a3c7f37bdf659bc22b394c42..c9ddd2fb569e70d9260ed7143a26b6366621783a 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -127,9 +127,8 @@
 {"name":"discordrb-webhooks","version":"3.5.0","platform":"ruby","checksum":"52fba8bce3b08059d4a41a1e73a9a152958e788a9330275450126b44f01c23b1"},
 {"name":"docile","version":"1.4.0","platform":"ruby","checksum":"5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3"},
 {"name":"domain_name","version":"0.5.20190701","platform":"ruby","checksum":"000a600454cb4a344769b2f10b531765ea7bd3a304fe47ed12e5ca1eab969851"},
-{"name":"doorkeeper","version":"5.7.1","platform":"ruby","checksum":"8b08f5946c62505be1a32f9094eb99eca32b280e956f515529e33b2b025bd628"},
+{"name":"doorkeeper","version":"5.8.0","platform":"ruby","checksum":"5abc747ee0eaa3140e165b41e937941f05d5ce5bcd8b8ed6718e6711623a8105"},
 {"name":"doorkeeper-device_authorization_grant","version":"1.0.3","platform":"ruby","checksum":"94c3ac12a0d50942850ecd58ed64298b397a5e903e8880cb68d4085600932679"},
-{"name":"doorkeeper-openid_connect","version":"1.8.9","platform":"ruby","checksum":"5709a991d113e946e1c7d722eb94af3bcbc0a121ece67edd72ce4d08a93bfcae"},
 {"name":"dotenv","version":"2.7.6","platform":"ruby","checksum":"2451ed5e8e43776d7a787e51d6f8903b98e446146c7ad143d5678cc2c409d547"},
 {"name":"dry-cli","version":"1.0.0","platform":"ruby","checksum":"28ead169f872954dd08910eb8ead59cf86cd18b4aab321e8eeefe945749569f0"},
 {"name":"dry-core","version":"1.0.1","platform":"ruby","checksum":"f32f4245e0f54e787f3708584ed8f7545aaf8dd99072e36f169312468ec5450d"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 936e3315eb705f7156d7f633b199eee6b92724b8..48a3a8f6df12f8632b2769b1f692eed078a49d19 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -159,6 +159,13 @@ PATH
   specs:
     diff_match_patch (0.1.0)
 
+PATH
+  remote: vendor/gems/doorkeeper-openid_connect
+  specs:
+    doorkeeper-openid_connect (1.8.9)
+      doorkeeper (>= 5.5, < 5.9)
+      jwt (>= 2.5)
+
 PATH
   remote: vendor/gems/gitlab-duo-workflow-service-client
   specs:
@@ -534,13 +541,10 @@ GEM
     docile (1.4.0)
     domain_name (0.5.20190701)
       unf (>= 0.0.5, < 1.0.0)
-    doorkeeper (5.7.1)
+    doorkeeper (5.8.0)
       railties (>= 5)
     doorkeeper-device_authorization_grant (1.0.3)
       doorkeeper (~> 5.5)
-    doorkeeper-openid_connect (1.8.9)
-      doorkeeper (>= 5.5, < 5.8)
-      jwt (>= 2.5)
     dotenv (2.7.6)
     dry-cli (1.0.0)
     dry-core (1.0.1)
@@ -2027,9 +2031,9 @@ DEPENDENCIES
   diff_match_patch (~> 0.1.0)!
   diffy (~> 3.4)
   discordrb-webhooks (~> 3.5)
-  doorkeeper (~> 5.6, >= 5.6.6)
+  doorkeeper (~> 5.8, >= 5.8.0)
   doorkeeper-device_authorization_grant (~> 1.0.0)
-  doorkeeper-openid_connect (~> 1.8, >= 1.8.7)
+  doorkeeper-openid_connect (~> 1.8)!
   duo_api (~> 1.3)
   ed25519 (~> 1.3.0)
   elasticsearch-api (= 7.17.11)
diff --git a/Gemfile.next.checksum b/Gemfile.next.checksum
index 4102eb6f693d9a60945e7ed8a3fb208be62cc825..f5f4c15647c311faee5f4af9e5405a940ccce04f 100644
--- a/Gemfile.next.checksum
+++ b/Gemfile.next.checksum
@@ -127,9 +127,8 @@
 {"name":"discordrb-webhooks","version":"3.5.0","platform":"ruby","checksum":"52fba8bce3b08059d4a41a1e73a9a152958e788a9330275450126b44f01c23b1"},
 {"name":"docile","version":"1.4.0","platform":"ruby","checksum":"5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3"},
 {"name":"domain_name","version":"0.5.20190701","platform":"ruby","checksum":"000a600454cb4a344769b2f10b531765ea7bd3a304fe47ed12e5ca1eab969851"},
-{"name":"doorkeeper","version":"5.7.1","platform":"ruby","checksum":"8b08f5946c62505be1a32f9094eb99eca32b280e956f515529e33b2b025bd628"},
+{"name":"doorkeeper","version":"5.8.0","platform":"ruby","checksum":"5abc747ee0eaa3140e165b41e937941f05d5ce5bcd8b8ed6718e6711623a8105"},
 {"name":"doorkeeper-device_authorization_grant","version":"1.0.3","platform":"ruby","checksum":"94c3ac12a0d50942850ecd58ed64298b397a5e903e8880cb68d4085600932679"},
-{"name":"doorkeeper-openid_connect","version":"1.8.9","platform":"ruby","checksum":"5709a991d113e946e1c7d722eb94af3bcbc0a121ece67edd72ce4d08a93bfcae"},
 {"name":"dotenv","version":"2.7.6","platform":"ruby","checksum":"2451ed5e8e43776d7a787e51d6f8903b98e446146c7ad143d5678cc2c409d547"},
 {"name":"drb","version":"2.2.1","platform":"ruby","checksum":"e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340"},
 {"name":"dry-cli","version":"1.0.0","platform":"ruby","checksum":"28ead169f872954dd08910eb8ead59cf86cd18b4aab321e8eeefe945749569f0"},
diff --git a/Gemfile.next.lock b/Gemfile.next.lock
index 1b814327380577edd6b68fefdef10f07adf255be..6b893f1bab4e16e09352081e5ed82d123e62665c 100644
--- a/Gemfile.next.lock
+++ b/Gemfile.next.lock
@@ -159,6 +159,13 @@ PATH
   specs:
     diff_match_patch (0.1.0)
 
+PATH
+  remote: vendor/gems/doorkeeper-openid_connect
+  specs:
+    doorkeeper-openid_connect (1.8.9)
+      doorkeeper (>= 5.5, < 5.9)
+      jwt (>= 2.5)
+
 PATH
   remote: vendor/gems/gitlab-duo-workflow-service-client
   specs:
@@ -543,13 +550,10 @@ GEM
     docile (1.4.0)
     domain_name (0.5.20190701)
       unf (>= 0.0.5, < 1.0.0)
-    doorkeeper (5.7.1)
+    doorkeeper (5.8.0)
       railties (>= 5)
     doorkeeper-device_authorization_grant (1.0.3)
       doorkeeper (~> 5.5)
-    doorkeeper-openid_connect (1.8.9)
-      doorkeeper (>= 5.5, < 5.8)
-      jwt (>= 2.5)
     dotenv (2.7.6)
     drb (2.2.1)
     dry-cli (1.0.0)
@@ -2054,9 +2058,9 @@ DEPENDENCIES
   diff_match_patch (~> 0.1.0)!
   diffy (~> 3.4)
   discordrb-webhooks (~> 3.5)
-  doorkeeper (~> 5.6, >= 5.6.6)
+  doorkeeper (~> 5.8, >= 5.8.0)
   doorkeeper-device_authorization_grant (~> 1.0.0)
-  doorkeeper-openid_connect (~> 1.8, >= 1.8.7)
+  doorkeeper-openid_connect (~> 1.8)!
   duo_api (~> 1.3)
   ed25519 (~> 1.3.0)
   elasticsearch-api (= 7.17.11)
diff --git a/vendor/gems/doorkeeper-openid_connect/.gitlab-ci.yml b/vendor/gems/doorkeeper-openid_connect/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..77259f8093d385cdfa718c360ea652c038a29650
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/.gitlab-ci.yml
@@ -0,0 +1,9 @@
+include:
+  - local: gems/gem.gitlab-ci.yml
+    inputs:
+      gem_name: "doorkeeper-openid_connect"
+      gem_path_prefix: "vendor/gems/"
+      bundle_gemfiles: ['gemfiles/doorkeeper_master.gemfile']
+      bundle_version: "2.5.11"
+variables:
+  BUNDLE_FROZEN: "false"
diff --git a/vendor/gems/doorkeeper-openid_connect/CHANGELOG.md b/vendor/gems/doorkeeper-openid_connect/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..588ff986bd8b14e61a8b53385e92177301033191
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/CHANGELOG.md
@@ -0,0 +1,288 @@
+## Unreleased
+
+- [#PR ID] Add your changelog entry here.
+
+## v1.8.9 (2024-05-07)
+
+- Support Doorkeeper 5.7
+
+## v1.8.8 (2024-02-26)
+
+- [#201] Add back typ=JWT to header
+
+## v1.8.7 (2023-05-18)
+
+- [#198] Fully qualify `JWT::JWK::Thumbprint` constant with :: (thanks to @stanhu)
+
+## v1.8.6 (2023-05-12)
+
+- [#194] Default to RFC 7638 kid fingerprint generation (thanks to @stanhu).
+
+## v1.8.5 (2023-02-02)
+
+- [#186] Simplify gem configuration reusing Doorkeeper configuration option DSL (thanks to @nbulaj).
+- [#182] Drop support for Ruby 2.6 and Rails 5 (thanks to @sato11).
+- [#188] Fix dookeeper-jwt compatibility (thanks to @zavan).
+
+## v1.8.4 (2023-02-01)
+
+Note that v1.8.4 changed the default kid fingerprint generation from RFC 7638 to a format
+based on the SHA256 digest of the key element. To restore the previous behavior, upgrade to v1.8.6.
+
+- [#177] Replace `json-jwt` with `ruby-jwt` to align with doorkeeper-jwt (thanks to @kristof-mattei).
+- [#185] Don't call active_record_options for Doorkeeper >= 5.6.3 (thanks to @zavan).
+- [#183] Stop render consent screen when user is not logged-in (thanks to @nov).
+
+## v1.8.3 (2022-12-02)
+
+- [#180] Add PKCE support to OpenID discovery endpoint (thanks to @stanhu).
+
+## v1.8.2 (2022-07-13)
+
+- [#168] Allow to use custom doorkeeper access grant model (thanks @nov).
+- [#170] Controllers inherit `Doorkeeper::AppliactionMetalController` (thanks @sato11).
+- [#171] Correctly override `AuthorizationsController` params (thanks to @nbulaj).
+
+## v1.8.1 (2022-02-09)
+
+- [#153] Fix ArgumentError caused by client credential validation introduced in Doorkeeper 5.5.1 (thanks to @CircumnavigatingFlatEarther)
+- [#161] Fix .well-known/openid-connect issuer (respond to block if provided) (thanks to @fkowal).
+- [#152] Expose oauth-authorization-server in routes (thanks to @mitar)
+
+## v1.8.0 (2021-05-11)
+
+No changes from v1.8.0-rc1.
+
+## v1.8.0-rc1 (2021-04-20)
+
+### Upgrading
+
+This gem now requires Doorkeeper 5.5 and Ruby 2.5.
+
+### Changes
+
+- [#138] Support form_post response mode (thanks to @linhdangduy)
+- [#144] Support block syntax for `issuer` configuration (thanks to @maxxsnake)
+- [#145] Register token flows with the strategy instead of the token class (thanks to @paukul)
+
+## v1.7.5 (2020-12-15)
+
+### Changes
+
+- [#126] Add discovery_url_options option for discovery endpoints URL generation (thanks to @phlegx)
+
+### Bugfixes
+
+- [#123] Remove reference to ApplicationRecord (thanks to @wheeyls)
+- [#124] Clone doorkeeper.grant_flows array before appending 'refresh_token' (thanks to @davidbasalla)
+- [#129] Avoid to use the config alias while supporting Doorkeeper 5.2 (thanks to @kymmt90)
+
+## v1.7.4 (2020-07-06)
+
+- [#119] Execute end_session_endpoint in the controllers context (thanks to @joeljunstrom)
+
+## v1.7.3 (2020-07-06)
+
+- [#111] Add configuration callback `select_account_for_resource_owner` to support the `prompt=select_account` param
+- [#112] Add grant_types_supported to discovery response
+- [#114] Fix user_info endpoint when used in api mode
+- [#116] Support Doorkeeper API (> 5.4) for registering custom grant flows.
+- [#117] Fix migration template to use Rails migrations DSL for association.
+- [#118] Use fragment urls for implicit flow error redirects (thanks to @joeljunstrom)
+
+## v1.7.2 (2020-05-20)
+
+### Changes
+
+- [#108] Add support for Doorkeeper 5.4
+- [#103] Add support for end_session_endpoint
+- [#109] Test against Ruby 2.7 & Rails 6.x
+
+## v1.7.1 (2020-02-07)
+
+### Upgrading
+
+This version adds `on_delete: :cascade` to the migration template for the `oauth_openid_requests` table, in order to fix #82.
+
+For existing installations, you should add a new migration in your application to drop the existing foreign key and replace it with a new one with `on_delete: :cascade` included. Depending on the database you're using and the size of your application this might bring up some concerns, but in most cases the following should be sufficient:
+
+```ruby
+class UpdateOauthOpenIdRequestsForeignKeys < ActiveRecord::Migration[5.2]
+  def up
+    remove_foreign_key(:oauth_openid_requests, column: :access_grant_id)
+    add_foreign_key(:oauth_openid_requests, :oauth_access_grants, column: :access_grant_id, on_delete: :cascade)
+  end
+
+  def down
+    remove_foreign_key(:oauth_openid_requests, column: :access_grant_id)
+    add_foreign_key(:oauth_openid_requests, :oauth_access_grants, column: :access_grant_id)
+  end
+end
+```
+
+### Bugfixes
+
+- [#96] Bump `json-jwt` because of CVE-2019-18848 (thanks to @leleabhinav)
+- [#97] Fixes for compatibility with Doorkeeper 5.2 (thanks to @linhdangduy)
+- [#98] Cascade deletes from `oauth_openid_requests` to `oauth_access_grants` (thanks to @manojmj92)
+- [#99] Fix `audience` claim when application is not set on access token (thanks to @ionut998)
+
+## v1.7.0 (2019-11-04)
+
+### Changes
+
+- [#85] This gem now requires Doorkeeper 5.2, Rails 5, and Ruby 2.4
+
+## v1.6.3 (2019-09-24)
+
+### Changes
+
+- [#81] Allow silent authentication without user consent (thanks to @jarosan)
+- Don't support Doorkeeper >= 5.2 due to breaking changes
+
+## v1.6.2 (2019-08-09)
+
+### Bugfixes
+
+- [#80] Check for client presence in controller, fixes a 500 error when `client_id` is missing (thanks to @cincospenguinos @urnf @isabellechalhoub)
+
+## v1.6.1 (2019-06-07)
+
+### Bugfixes
+
+- [#75] Fix return value for `after_successful_response` (thanks to @daveed)
+
+### Changes
+
+- [#72] Add `revocation_endpoint` and `introspection_endpoint` to discovery response (thanks to @scarfacedeb)
+
+## v1.6.0 (2019-03-06)
+
+### Changes
+
+- [#70] This gem now requires Doorkeeper 5.0, and actually has done so since v1.5.4 (thanks to @michaelglass)
+
+## v1.5.5 (2019-03-03)
+
+- [#69] Return `crv` parameter for EC keys (thanks to @marco-nicola)
+
+## v1.5.4 (2019-02-15)
+
+### Bugfixes
+
+- [#66] Fix an open redirect vulnerability ([CVE-2019-9837](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9837), thanks to @meagar)
+- [#67] Don't delete existing tokens with `prompt=consent` (thanks to @nov)
+
+### Changes
+
+- [#62] Support customization of redirect params in `id_token` and `id_token token` responses (thanks to @meagar)
+
+## v1.5.3 (2019-01-19)
+
+### Bugfixes
+
+- [#60] Don't break native authorization in Doorkeeper 5.x
+
+### Changes
+
+- [#58] Use versioned migrations for Rails 5.x (thanks to @tvongaza)
+
+## v1.5.2 (2018-09-04)
+
+### Changes
+
+- [#56] The previous release was a bit premature, this fixes some compatibility issues with Doorkeeper 5.x
+
+## v1.5.1 (2018-09-04)
+
+### Changes
+
+- [#55] This gem is now compatible with Doorkeeper 5.x
+
+## v1.5.0 (2018-06-27)
+
+### Features
+
+- [#52] Custom claims can now also be returned directly in the ID token, see the updated README for usage instructions
+
+## v1.4.0 (2018-05-31)
+
+### Upgrading
+
+- Support for Ruby versions older than 2.3 was dropped
+
+### Features
+
+- Redirect errors per Section 3.1.2.6 of OpenID Connect 1.0 (by @ryands)
+- Set `id_token` when it's nil in token response (it's used in `refresh_token` requests) (by @Miouge1)
+
+## v1.3.0 (2018-03-05)
+
+### Features
+
+- Support for Implicit Flow (`response_type=id_token` and `response_type=id_token token`),
+  see the updated README for usage instructions (by @nashby, @nhance and @stevenvegt)
+
+## v1.2.0 (2017-08-31)
+
+### Upgrading
+
+- The configuration setting `jws_private_key` was renamed to `signing_key`, you can still use the old name until it's removed in the next major release
+
+### Features
+
+- Support for pairwise subject identifiers (by @travisofthenorth)
+- Support for EC and HMAC signing algorithms (by @110y)
+- Claims now receive an optional third `access_token` argument which allow you to dynamically adjust claim values based on the client's token (by @gigr)
+
+### Bugfixes
+
+## v1.1.2 (2017-01-18)
+
+### Bugfixes
+
+- Fixes the `undefined local variable or method 'pre_auth'` error
+
+## v1.1.1 (2017-01-18)
+
+#### Upgrading
+
+- The configuration setting `jws_public_key` wasn't actually used, it's deprecated now and will be removed in the next major release
+- The undocumented shorthand `to_proc` syntax for defining claims (`claim :user, &:name`) is not supported anymore
+
+#### Features
+
+- Claims now receive an optional second `scopes` argument which allow you to dynamically adjust claim values based on the requesting applications' scopes (by @nbibler)
+- The `prompt` parameter values `login` and `consent` are now supported
+- The configuration setting `protocol` was added (by @gigr)
+
+#### Bugfixes
+
+- Standard Claims are now mapped correctly to their default scopes (by @tylerhunt)
+- Blank `nonce` parameters are now ignored
+
+#### Changes
+
+- `nil` values and empty strings are now removed from the UserInfo and IdToken responses
+- Allow `json-jwt` dependency at ~> 1.6. (by @nbibler)
+- Configuration blocks no longer internally use `instance_eval` which previously gave undocumented and unexpected `self` access to the caller (by @nbibler)
+
+## v1.1.0 (2016-11-30)
+
+This release is a general clean-up and adds support for some advanced OpenID Connect features.
+
+#### Upgrading
+
+- This version adds a table to store temporary nonces, use the generator `doorkeeper:openid_connect:migration` to create a migration
+- Implement the new configuration callbacks `auth_time_from_resource_owner` and `reauthenticate_resource_owner` to support advanced features
+
+#### Features
+
+- Add discovery endpoint	 ([a16caa8](/../../commit/a16caa8))
+- Add webfinger and keys endpoints for discovery	 ([f70898b](/../../commit/f70898b))
+- Add supported claims to discovery response	 ([1d8f9ea](/../../commit/1d8f9ea))
+- Support prompt=none parameter	 ([c775d8b](/../../commit/c775d8b))
+- Store and return nonces in IdToken responses	 ([d28ca8c](/../../commit/d28ca8c))
+- Add generator for initializer	 ([80399fd](/../../commit/80399fd))
+- Support max_age parameter	 ([aabe3aa](/../../commit/aabe3aa))
+- Respect scope grants in UserInfo response	 ([25f2170](/../../commit/25f2170))
diff --git a/vendor/gems/doorkeeper-openid_connect/CONTRIBUTING.md b/vendor/gems/doorkeeper-openid_connect/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..5cc59a017b27a851f6e280221eab8591ecfdc083
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# Contributing
+
+## Workflow
+
+We are using the [Feature Branch Workflow (also known as GitHub Flow)](https://guides.github.com/introduction/flow/), and prefer delivery as pull requests.
+
+Our first line of defense is the [Travis CI](https://travis-ci.org/doorkeeper-gem/doorkeeper-openid_connect) build defined within [.travis.yml](.travis.yml) and triggered for every pull request.
+
+Create a feature branch:
+
+```sh
+git checkout -B feature/contributing
+```
+
+## Creating Good Commits
+
+The cardinal rule for creating good commits is to ensure there is only one
+"logical change" per commit. Why is this an important rule?
+
+* The smaller the amount of code being changed, the quicker & easier it is to
+  review & identify potential flaws.
+
+* If a change is found to be flawed later, it may be necessary to revert the
+  broken commit. This is much easier to do if there are not other unrelated
+  code changes entangled with the original commit.
+
+* When troubleshooting problems using Git's bisect capability, small well
+  defined changes will aid in isolating exactly where the code problem was
+  introduced.
+
+* When browsing history using Git annotate/blame, small well defined changes
+  also aid in isolating exactly where & why a piece of code came from.
+
+Things to avoid when creating commits:
+
+* Mixing whitespace changes with functional code changes.
+* Mixing two unrelated functional changes.
+* Sending large new features in a single giant commit.
+
+## Release process
+
+- Bump version in `lib/doorkeeper/openid_connect/version.rb`.
+- Update `CHANGELOG.md`.
+- Commit all changes.
+- Tag release and publish gem with `rake release`.
+- [Publish a new release on GitHub](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/releases/new), using the created tag and the new entries in `CHANGELOG.md`.
diff --git a/vendor/gems/doorkeeper-openid_connect/Gemfile b/vendor/gems/doorkeeper-openid_connect/Gemfile
new file mode 100644
index 0000000000000000000000000000000000000000..9a2cbd3fa5b25802e1e14c10c53fe1bfeeef61ad
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/Gemfile
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+# use Rails version specified by environment
+ENV['rails'] ||= '6.0.0'
+gem 'rails', "~> #{ENV['rails']}"
+gem 'rails-controller-testing'
+
+gem 'rubocop', '~> 1.6'
+gem 'rubocop-performance', require: false
+gem 'rubocop-rails', require: false
+gem 'rubocop-rspec', require: false
+
+gemspec
diff --git a/vendor/gems/doorkeeper-openid_connect/LICENSE.txt b/vendor/gems/doorkeeper-openid_connect/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..31b068d048f0c45856da5790614cee1bffa56585
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/LICENSE.txt
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2014 PlayOn! Sports
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/gems/doorkeeper-openid_connect/README.md b/vendor/gems/doorkeeper-openid_connect/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9fde3a9515cb986e3812df81ebd30124aab3009b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/README.md
@@ -0,0 +1,342 @@
+# Doorkeeper::OpenidConnect
+
+This is a fork of [doorkeeper-openid_connect](https://github.com/doorkeeper-gem/doorkeeper-openid_connect) to support:
+
+- Doorkeeper version 5.8.0
+- This gem can be unvendored once [PR 213](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/pull/213) is merged and released.
+
+[![Build Status](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/workflows/CI/badge.svg?branch=master)](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/actions)
+[![Code Climate](https://codeclimate.com/github/doorkeeper-gem/doorkeeper-openid_connect.svg)](https://codeclimate.com/github/doorkeeper-gem/doorkeeper-openid_connect)
+[![Gem Version](https://badge.fury.io/rb/doorkeeper-openid_connect.svg)](https://rubygems.org/gems/doorkeeper-openid_connect)
+
+#### :warning: **This project is looking for maintainers, see [this issue](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/issues/89).**
+
+This library implements an [OpenID Connect](http://openid.net/connect/) authentication provider for Rails applications on top of the [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) OAuth 2.0 framework.
+
+OpenID Connect is a single-sign-on and identity layer with a [growing list of server and client implementations](http://openid.net/developers/libraries/). If you're looking for a client in Ruby check out [omniauth_openid_connect](https://github.com/m0n9oose/omniauth_openid_connect/).
+
+## Table of Contents
+
+- [Status](#status)
+  - [Known Issues](#known-issues)
+  - [Example Applications](#example-applications)
+- [Installation](#installation)
+- [Configuration](#configuration)
+  - [Scopes](#scopes)
+  - [Claims](#claims)
+  - [Routes](#routes)
+  - [Nonces](#nonces)
+  - [Internationalization (I18n)](#internationalization-i18n)
+- [Development](#development)
+- [License](#license)
+- [Sponsors](#sponsors)
+
+## Status
+
+The following parts of [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) are currently supported:
+
+- [Authentication using the Authorization Code Flow](http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth)
+- [Authentication using the Implicit Flow](http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth)
+- [Requesting Claims using Scope Values](http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims)
+- [UserInfo Endpoint](http://openid.net/specs/openid-connect-core-1_0.html#UserInfo)
+- [Normal Claims](http://openid.net/specs/openid-connect-core-1_0.html#NormalClaims)
+- [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html)
+
+In addition we also support most of [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) for automatic configuration discovery.
+
+Take a look at the [DiscoveryController](app/controllers/doorkeeper/openid_connect/discovery_controller.rb) for more details on supported features.
+
+### Known Issues
+
+- Doorkeeper's API mode (`Doorkeeper.configuration.api_only`) is not properly supported yet
+
+### Example Applications
+
+- [GitLab](https://gitlab.com/gitlab-org/gitlab-ce) ([original MR](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8018))
+- [Testing app for this gem](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/tree/master/spec/dummy)
+
+## Installation
+
+Make sure your application is already set up with [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper#installation).
+
+Add this line to your application's `Gemfile` and run `bundle install`:
+
+```ruby
+gem 'doorkeeper-openid_connect'
+```
+
+Run the installation generator to update routes and create the initializer:
+
+```sh
+rails generate doorkeeper:openid_connect:install
+```
+
+Generate a migration for Active Record (other ORMs are currently not supported):
+
+```sh
+rails generate doorkeeper:openid_connect:migration
+rake db:migrate
+```
+
+If you're upgrading from an earlier version, check [CHANGELOG.md](CHANGELOG.md) for upgrade instructions.
+
+## Configuration
+
+Make sure you've [configured Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper#configuration) before continuing.
+
+Verify your settings in `config/initializers/doorkeeper.rb`:
+
+- `resource_owner_authenticator`
+  - This callback needs to returns a falsey value if the current user can't be determined:
+
+    ```ruby
+    resource_owner_authenticator do
+      if current_user
+        current_user
+      else
+        redirect_to(new_user_session_url)
+        nil
+      end
+    end
+    ```
+
+- `grant_flows`
+  - If you want to use `id_token` or `id_token token` response types you need to add `implicit_oidc` to `grant_flows`:
+
+    ```ruby
+    grant_flows %w(authorization_code implicit_oidc)
+    ```
+
+The following settings are required in `config/initializers/doorkeeper_openid_connect.rb`:
+
+- `issuer`
+  - Identifier for the issuer of the response (i.e. your application URL). The value is a case sensitive URL using the `https` scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components.
+  - You can either pass a string value, or a block to generate the issuer dynamically based on the `resource_owner` and `application` or [request](app/controllers/doorkeeper/openid_connect/discovery_controller.rb#L123) passed to the block.
+- `subject`
+  - Identifier for the resource owner (i.e. the authenticated user). A locally unique and never reassigned identifier within the issuer for the end-user, which is intended to be consumed by the client. The value is a case-sensitive string and must not exceed 255 ASCII characters in length.
+  - The database ID of the user is an acceptable choice if you don't mind leaking that information.
+  - If you want to provide a different subject identifier to each client, use [pairwise subject identifier](http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes) with configurations like below.
+
+    ```ruby
+    # config/initializers/doorkeeper_openid_connect.rb
+    Doorkeeper::OpenidConnect.configure do
+    # ...
+      subject_types_supported [:pairwise]
+
+      subject do |resource_owner, application|
+        Digest::SHA256.hexdigest("#{resource_owner.id}#{URI.parse(application.redirect_uri).host}#{'your_secret_salt'}")
+      end
+    # ...
+    end
+    ```
+
+- `signing_key`
+  - Private key to be used for [JSON Web Signature](https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31).
+  - You can generate a private key with the `openssl` command, see e.g. [Generate an RSA keypair using OpenSSL](https://en.wikibooks.org/wiki/Cryptography/Generate_a_keypair_using_OpenSSL).
+  - You should not commit the key to your repository, but use an external file (in combination with `File.read`) and/or the [dotenv-rails](https://github.com/bkeepers/dotenv) gem (in combination with `ENV[...]`).
+- `signing_algorithm`
+  - The encryption type of the private key which defaults to `:rs256`. The list of supported algorithms can be found [here](https://github.com/nov/json-jwt/wiki/JWE#supported-algorithms)
+- `resource_owner_from_access_token`
+  - Defines how to translate the Doorkeeper access token to a resource owner model.
+
+The following settings are optional, but recommended for better client compatibility:
+
+- `auth_time_from_resource_owner`
+  - Returns the time of the user's last login, this can be a `Time`, `DateTime`, or any other class that responds to `to_i`
+  - Required to support the `max_age` parameter and the `auth_time` claim.
+- `reauthenticate_resource_owner`
+  - Defines how to trigger reauthentication for the current user (e.g. display a password prompt, or sign-out the user and redirect to the login form).
+  - Required to support the `max_age` and `prompt=login` parameters.
+  - The block is executed in the controller's scope, so you have access to methods like `params`, `redirect_to` etc.
+- `select_account_for_resource_owner`
+  - Defines how to trigger account selection to choose the current login user.
+  - Required to support the `prompt=select_account` parameter.
+  - The block is executed in the controller's scope, so you have access to methods like `params`, `redirect_to` etc.
+
+The following settings are optional:
+
+- `expiration`
+  - Expiration time after which the ID Token must not be accepted for processing by clients.
+  - The default is 120 seconds
+
+- `protocol`
+  - The protocol to use when generating URIs for the discovery endpoints.
+  - The default is `https` for production, and `http` for all other environments
+  - Note that the OIDC specification mandates HTTPS, so you shouldn't change this
+    for production environments unless you have a really good reason!
+
+- `end_session_endpoint`
+  - The URL that the user is redirected to after ending the session on the client.
+  - Used by implementations like <https://github.com/IdentityModel/oidc-client-js>.
+  - The block is executed in the controller's scope, so you have access to your route helpers.
+
+- `discovery_url_options`
+  - The URL options for every available endpoint to use when generating the endpoint URL in the
+    discovery response. Available endpoints: `authorization`, `token`, `revocation`,
+    `introspection`, `userinfo`, `jwks`, `webfinger`.
+  - This option requires option keys with an available endpoint and
+    [URL options](https://api.rubyonrails.org/v6.0.3.3/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for)
+    as value.
+  - The default is to use the request host, just like all the other URLs in the discovery response.
+  - This is useful when you want endpoints to use a different URL than other requests.
+    For example, if your Doorkeeper server is behind a firewall with other servers, you might want
+    other servers to use an "internal" URL to communicate with Doorkeeper, but you want to present
+    an "external" URL to end-users for authentication requests. Note that this setting does not
+    actually change the URL that your Doorkeeper server responds on - that is outside the scope of
+    Doorkeeper.
+
+    ```ruby
+    # config/initializers/doorkeeper_openid_connect.rb
+    Doorkeeper::OpenidConnect.configure do
+    # ...
+      discovery_url_options do |request|
+        {
+          authorization: { host: 'host.example.com' },
+          jwks:          { protocol: request.ssl? ? :https : :http }
+        }
+      end
+    # ...
+    end
+    ```
+
+### Scopes
+
+To perform authentication over OpenID Connect, an OAuth client needs to request the `openid` scope. This scope needs to be enabled using either `optional_scopes` in the global Doorkeeper configuration in `config/initializers/doorkeeper.rb`, or by adding it to any OAuth application's `scope` attribute.
+
+> Note that any application defining its own scopes won't inherit the scopes defined in the initializer, so you might have to update existing applications as well.
+>
+> See [Using Scopes](https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes) in the Doorkeeper wiki for more information.
+
+### Claims
+
+Claims can be defined in a `claims` block inside `config/initializers/doorkeeper_openid_connect.rb`:
+
+```ruby
+Doorkeeper::OpenidConnect.configure do
+  claims do
+    claim :email do |resource_owner|
+      resource_owner.email
+    end
+
+    claim :full_name do |resource_owner|
+      "#{resource_owner.first_name} #{resource_owner.last_name}"
+    end
+
+    claim :preferred_username, scope: :openid do |resource_owner, scopes, access_token|
+      # Pass the resource_owner's preferred_username if the application has
+      # `profile` scope access. Otherwise, provide a more generic alternative.
+      scopes.exists?(:profile) ? resource_owner.preferred_username : "summer-sun-9449"
+    end
+
+    claim :groups, response: [:id_token, :user_info] do |resource_owner|
+      resource_owner.groups
+    end
+  end
+end
+```
+
+Each claim block will be passed:
+
+- the `resource_owner`, which is the return value of `resource_owner_authenticator` in your initializer
+- the `scopes` granted by the access token, which is an instance of `Doorkeeper::OAuth::Scopes`
+- the `access_token` itself, which is an instance of `Doorkeeper::AccessToken`
+
+By default all custom claims are only returned from the `UserInfo` endpoint and not included in the ID token. You can optionally pass a `response:` keyword with one or both of the symbols `:id_token` or `:user_info` to specify where the claim should be returned.
+
+You can also pass a `scope:` keyword argument on each claim to specify which OAuth scope should be required to access the claim. If you define any of the defined [Standard Claims](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) they will by default use their [corresponding scopes](http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) (`profile`, `email`, `address` and `phone`), and any other claims will by default use the `profile` scope. Again, to use any of these scopes you need to enable them as described above.
+
+### Routes
+
+The installation generator will update your `config/routes.rb` to define all required routes:
+
+``` ruby
+Rails.application.routes.draw do
+  use_doorkeeper_openid_connect
+  # your routes
+end
+```
+
+This will mount the following routes:
+
+```
+GET   /oauth/userinfo
+POST  /oauth/userinfo
+GET   /oauth/discovery/keys
+GET   /.well-known/openid-configuration
+GET   /.well-known/webfinger
+```
+
+With the exception of the hard-coded `/.well-known` paths (see [RFC 5785](https://tools.ietf.org/html/rfc5785)) you can customize routes in the same way as with Doorkeeper, please refer to [this page on their wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes#version--05-1).
+
+### Nonces
+
+To support clients who send nonces you have to tweak Doorkeeper's authorization view so the parameter is passed on.
+
+If you don't already have custom templates, run this generator in your Rails application to add them:
+
+```sh
+rails generate doorkeeper:views
+```
+
+Then tweak the template as follows:
+
+```patch
+--- i/app/views/doorkeeper/authorizations/new.html.erb
++++ w/app/views/doorkeeper/authorizations/new.html.erb
+@@ -26,6 +26,7 @@
+       <%= hidden_field_tag :state, @pre_auth.state %>
+       <%= hidden_field_tag :response_type, @pre_auth.response_type %>
+       <%= hidden_field_tag :scope, @pre_auth.scope %>
++      <%= hidden_field_tag :nonce, @pre_auth.nonce %>
+       <%= submit_tag t('doorkeeper.authorizations.buttons.authorize'), class: "btn btn-success btn-lg btn-block" %>
+     <% end %>
+     <%= form_tag oauth_authorization_path, method: :delete do %>
+@@ -34,6 +35,7 @@
+       <%= hidden_field_tag :state, @pre_auth.state %>
+       <%= hidden_field_tag :response_type, @pre_auth.response_type %>
+       <%= hidden_field_tag :scope, @pre_auth.scope %>
++      <%= hidden_field_tag :nonce, @pre_auth.nonce %>
+       <%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %>
+     <% end %>
+   </div>
+```
+
+### Internationalization (I18n)
+
+We use Rails locale files for error messages and scope descriptions, see [config/locales/en.yml](config/locales/en.yml). You can override these by adding them to your own translations in `config/locale`.
+
+## Development
+
+Run `bundle install` to setup all development dependencies.
+
+To run all specs:
+
+```sh
+bundle exec rake spec
+```
+
+To generate and run migrations in the test application:
+
+```sh
+bundle exec rake migrate
+```
+
+To run the local engine server:
+
+```sh
+bundle exec rake server
+```
+
+By default, the latest Rails version is used. To use a specific version run:
+
+```
+rails=4.2.0 bundle update
+```
+
+## License
+
+Doorkeeper::OpenidConnect is released under the [MIT License](http://www.opensource.org/licenses/MIT).
+
+## Sponsors
+
+Initial development of this project was sponsored by [PlayOn! Sports](https://github.com/playon).
diff --git a/vendor/gems/doorkeeper-openid_connect/Rakefile b/vendor/gems/doorkeeper-openid_connect/Rakefile
new file mode 100644
index 0000000000000000000000000000000000000000..a6fe1e73c4d57664927aff2a5217d1792b35b070
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/Rakefile
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+ENV['RAILS_ENV'] ||= 'test'
+
+require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+
+RSpec::Core::RakeTask.new
+
+task default: :spec
+task test: :spec
+
+desc 'Generate and run migrations in the test application'
+task :migrate do
+  Dir.chdir('spec/dummy') do
+    system('bin/rails generate doorkeeper:openid_connect:migration')
+    system('bin/rake db:migrate')
+  end
+end
+
+desc 'Run server in the test application'
+task :server do
+  Dir.chdir('spec/dummy') do
+    system('bin/rails server')
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/app/controllers/concerns/doorkeeper/openid_connect/authorizations_extension.rb b/vendor/gems/doorkeeper-openid_connect/app/controllers/concerns/doorkeeper/openid_connect/authorizations_extension.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6a906b7d1a76218442435733ec17de06abf115be
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/app/controllers/concerns/doorkeeper/openid_connect/authorizations_extension.rb
@@ -0,0 +1,12 @@
+module Doorkeeper
+  module OpenidConnect
+    module AuthorizationsExtension
+      private
+
+      def pre_auth_param_fields
+        super.append(:nonce)
+      end
+    end
+  end
+end
+
diff --git a/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/discovery_controller.rb b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/discovery_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f834139c596a45ca5495cd525c8d6db5a4f21b7b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/discovery_controller.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class DiscoveryController < ::Doorkeeper::ApplicationMetalController
+      include Doorkeeper::Helpers::Controller
+
+      WEBFINGER_RELATION = 'http://openid.net/specs/connect/1.0/issuer'
+
+      def provider
+        render json: provider_response
+      end
+
+      def webfinger
+        render json: webfinger_response
+      end
+
+      def keys
+        render json: keys_response
+      end
+
+      private
+
+      def provider_response
+        doorkeeper = ::Doorkeeper.configuration
+        openid_connect = ::Doorkeeper::OpenidConnect.configuration
+
+        {
+          issuer: issuer,
+          authorization_endpoint: oauth_authorization_url(authorization_url_options),
+          token_endpoint: oauth_token_url(token_url_options),
+          revocation_endpoint: oauth_revoke_url(revocation_url_options),
+          introspection_endpoint: respond_to?(:oauth_introspect_url) ? oauth_introspect_url(introspection_url_options) : nil,
+          userinfo_endpoint: oauth_userinfo_url(userinfo_url_options),
+          jwks_uri: oauth_discovery_keys_url(jwks_url_options),
+          end_session_endpoint: instance_exec(&openid_connect.end_session_endpoint),
+
+          scopes_supported: doorkeeper.scopes,
+
+          # TODO: support id_token response type
+          response_types_supported: doorkeeper.authorization_response_types,
+          response_modes_supported: response_modes_supported(doorkeeper),
+          grant_types_supported: grant_types_supported(doorkeeper),
+
+          # TODO: look into doorkeeper-jwt_assertion for these
+          #  'client_secret_jwt',
+          #  'private_key_jwt'
+          token_endpoint_auth_methods_supported: %w[client_secret_basic client_secret_post],
+
+          subject_types_supported: openid_connect.subject_types_supported,
+
+          id_token_signing_alg_values_supported: [
+            ::Doorkeeper::OpenidConnect.signing_algorithm
+          ],
+
+          claim_types_supported: [
+            'normal',
+
+            # TODO: support these
+            # 'aggregated',
+            # 'distributed',
+          ],
+
+          claims_supported: %w[
+            iss
+            sub
+            aud
+            exp
+            iat
+          ] | openid_connect.claims.to_h.keys,
+
+          code_challenge_methods_supported: code_challenge_methods_supported(doorkeeper),
+        }.compact
+      end
+
+      def grant_types_supported(doorkeeper)
+        grant_types_supported = doorkeeper.grant_flows.dup
+        grant_types_supported << 'refresh_token' if doorkeeper.refresh_token_enabled?
+        grant_types_supported
+      end
+
+      def response_modes_supported(doorkeeper)
+        doorkeeper.authorization_response_flows.flat_map(&:response_mode_matches).uniq
+      end
+
+      def code_challenge_methods_supported(doorkeeper)
+        return unless doorkeeper.access_grant_model.pkce_supported?
+
+        %w[plain S256]
+      end
+
+      def webfinger_response
+        {
+          subject: params.require(:resource),
+          links: [
+            {
+              rel: WEBFINGER_RELATION,
+              href: root_url(webfinger_url_options),
+            }
+          ]
+        }
+      end
+
+      def keys_response
+        signing_key = Doorkeeper::OpenidConnect.signing_key_normalized
+
+        {
+          keys: [
+            signing_key.merge(
+              use: 'sig',
+              alg: Doorkeeper::OpenidConnect.signing_algorithm
+            )
+          ]
+        }
+      end
+
+      def protocol
+        Doorkeeper::OpenidConnect.configuration.protocol.call
+      end
+
+      def discovery_url_options
+        Doorkeeper::OpenidConnect.configuration.discovery_url_options.call(request)
+      end
+
+      def discovery_url_default_options
+        {
+          protocol: protocol
+        }
+      end
+
+      def issuer
+        if Doorkeeper::OpenidConnect.configuration.issuer.respond_to?(:call)
+          Doorkeeper::OpenidConnect.configuration.issuer.call(request).to_s
+        else
+          Doorkeeper::OpenidConnect.configuration.issuer
+        end
+      end
+
+      %i[authorization token revocation introspection userinfo jwks webfinger].each do |endpoint|
+        define_method :"#{endpoint}_url_options" do
+          discovery_url_default_options.merge(discovery_url_options[endpoint.to_sym] || {})
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c6ace1aab2a7d131e7343379e821a8c589bac64b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class UserinfoController < ::Doorkeeper::ApplicationMetalController
+      before_action -> { doorkeeper_authorize! :openid }
+
+      def show
+        render json: Doorkeeper::OpenidConnect::UserInfo.new(doorkeeper_token), status: :ok
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/bin/console b/vendor/gems/doorkeeper-openid_connect/bin/console
new file mode 100755
index 0000000000000000000000000000000000000000..8c3eaafde17c761e21bf2bd88e2bbcfadba8cd0c
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/bin/console
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'bundler/setup'
+Bundler.require :default
+
+require 'doorkeeper/openid_connect'
+
+require 'pry'
+Pry.start
diff --git a/vendor/gems/doorkeeper-openid_connect/bin/setup b/vendor/gems/doorkeeper-openid_connect/bin/setup
new file mode 100755
index 0000000000000000000000000000000000000000..dce67d860af47a4eb630117ce03624bae45dcf26
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/bin/setup
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+IFS=$'\n\t'
+set -vx
+
+bundle install
+
+# Do any other automated setup that you need to do here
diff --git a/vendor/gems/doorkeeper-openid_connect/config/locales/en.yml b/vendor/gems/doorkeeper-openid_connect/config/locales/en.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1bed506b2cf19142aac85a474e901e8bab8f5253
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/config/locales/en.yml
@@ -0,0 +1,23 @@
+en:
+  doorkeeper:
+    scopes:
+      openid: 'Authenticate your account'
+      profile: 'View your profile information'
+      email: 'View your email address'
+      address: 'View your physical address'
+      phone: 'View your phone number'
+    errors:
+      messages:
+        login_required: 'The authorization server requires end-user authentication'
+        consent_required: 'The authorization server requires end-user consent'
+        interaction_required: 'The authorization server requires end-user interaction'
+        account_selection_required: 'The authorization server requires end-user account selection'
+    openid_connect:
+      errors:
+        messages:
+          # Configuration error messages
+          resource_owner_from_access_token_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.resource_owner_from_access_token missing configuration.'
+          auth_time_from_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.auth_time_from_resource_owner missing configuration.'
+          reauthenticate_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.reauthenticate_resource_owner missing configuration.'
+          select_account_for_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.select_account_for_resource_owner missing configuration.'
+          subject_not_configured: 'ID Token generation failed due to Doorkeeper::OpenidConnect.configure.subject missing configuration.'
diff --git a/vendor/gems/doorkeeper-openid_connect/doorkeeper-openid_connect.gemspec b/vendor/gems/doorkeeper-openid_connect/doorkeeper-openid_connect.gemspec
new file mode 100644
index 0000000000000000000000000000000000000000..bb050b8a6b4cf2909d8fce226eb7b3cbb99517b9
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/doorkeeper-openid_connect.gemspec
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+$LOAD_PATH.push File.expand_path('lib', __dir__)
+require 'doorkeeper/openid_connect/version'
+
+Gem::Specification.new do |spec|
+  spec.name          = 'doorkeeper-openid_connect'
+  spec.version       = Doorkeeper::OpenidConnect::VERSION
+  spec.authors       = ['Sam Dengler', 'Markus Koller', 'Nikita Bulai']
+  spec.email         = ['sam.dengler@playonsports.com', 'markus-koller@gmx.ch', 'bulajnikita@gmail.com']
+  spec.homepage      = 'https://github.com/doorkeeper-gem/doorkeeper-openid_connect'
+  spec.summary       = 'OpenID Connect extension for Doorkeeper.'
+  spec.description   = 'OpenID Connect extension for Doorkeeper.'
+  spec.license       = 'MIT'
+
+  spec.files = Dir[
+    "{app,config,lib}/**/*",
+    "CHANGELOG.md",
+    "LICENSE.txt",
+    "README.md",
+  ]
+  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+  spec.require_paths = ['lib']
+
+  spec.required_ruby_version = '>= 2.7'
+
+  spec.add_runtime_dependency 'doorkeeper', '>= 5.5', '< 5.9'
+  spec.add_runtime_dependency 'jwt', '>= 2.5'
+
+  spec.add_development_dependency 'conventional-changelog', '~> 1.2'
+  spec.add_development_dependency 'factory_bot'
+  spec.add_development_dependency 'pry-byebug'
+  spec.add_development_dependency 'rspec-rails'
+  spec.add_development_dependency 'sqlite3', '>= 1.3.6'
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/doorkeeper_master.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/doorkeeper_master.gemfile
new file mode 100644
index 0000000000000000000000000000000000000000..5157472158ef624c7ddbd05184b9a89653b2d116
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/doorkeeper_master.gemfile
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'rails', '~> 7.0.0'
+gem 'rails-controller-testing'
+gem 'doorkeeper', git: 'https://github.com/doorkeeper-gem/doorkeeper.git'
+
+gemspec path: '../'
diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.0.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.0.gemfile
new file mode 100644
index 0000000000000000000000000000000000000000..39898608de60e967b6b91a4216e0860cde4455b1
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.0.gemfile
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'rails', '~> 6.0.0'
+gem 'rails-controller-testing'
+
+gemspec path: '../'
diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.1.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.1.gemfile
new file mode 100644
index 0000000000000000000000000000000000000000..df88b047af292d1124fee9c46be860844e7c4af6
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.1.gemfile
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'rails', '~> 6.1.0'
+gem 'rails-controller-testing'
+
+gemspec path: '../'
diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_7.0.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_7.0.gemfile
new file mode 100644
index 0000000000000000000000000000000000000000..4032a5772ee3390642a9f97a6b417809cc892b78
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_7.0.gemfile
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'rails', '~> 7.0.0'
+gem 'rails-controller-testing'
+
+gemspec path: '../'
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_request.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e6054508cc04c7c616ce02cdbe2c1a31549345a8
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_request.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OAuth
+    class IdTokenRequest
+      attr_accessor :pre_auth, :auth, :resource_owner
+
+      def initialize(pre_auth, resource_owner)
+        @pre_auth       = pre_auth
+        @resource_owner = resource_owner
+      end
+
+      def authorize
+        @auth = Authorization::Token.new(pre_auth, resource_owner)
+        if @auth.respond_to?(:issue_token!)
+          @auth.issue_token!
+        else
+          @auth.issue_token
+        end
+        response
+      end
+
+      def deny
+        pre_auth.error = :access_denied
+        pre_auth.error_response
+      end
+
+      private
+
+      def response
+        id_token = Doorkeeper::OpenidConnect::IdToken.new(auth.token, pre_auth.nonce)
+
+        IdTokenResponse.new(pre_auth, auth, id_token)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_response.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_response.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a555f2d2d60e1961951893d996caeda126790f73
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_response.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OAuth
+    class IdTokenResponse < BaseResponse
+      include OAuth::Helpers
+
+      attr_accessor :pre_auth, :auth, :id_token
+
+      def initialize(pre_auth, auth, id_token)
+        @pre_auth = pre_auth
+        @auth = auth
+        @id_token = id_token
+      end
+
+      def redirectable?
+        true
+      end
+
+      def body
+        {
+          expires_in: auth.token.expires_in_seconds,
+          state: pre_auth.state,
+          id_token: id_token.as_jws_token
+        }
+      end
+
+      def redirect_uri
+        Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_request.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cfcfb4ee01bbd4e18b297eed48e7608d0fd3115c
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_request.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OAuth
+    class IdTokenTokenRequest < IdTokenRequest
+      private
+
+      def response
+        id_token_token = Doorkeeper::OpenidConnect::IdTokenToken.new(auth.token, pre_auth.nonce)
+
+        IdTokenTokenResponse.new(pre_auth, auth, id_token_token)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_response.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_response.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ac212d5b5340ab9a6e3155cec55a59926ed40028
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_response.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OAuth
+    class IdTokenTokenResponse < IdTokenResponse
+      def body
+        super.merge({
+          access_token: auth.token.token,
+          token_type: auth.token.token_type
+        })
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4d0de3c3803ccf0d6d474b36fdf85e72aaa70e31
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'doorkeeper'
+require 'active_model'
+require 'jwt'
+
+require 'doorkeeper/request'
+require 'doorkeeper/request/id_token'
+require 'doorkeeper/request/id_token_token'
+require 'doorkeeper/oauth/id_token_request'
+require 'doorkeeper/oauth/id_token_token_request'
+require 'doorkeeper/oauth/id_token_response'
+require 'doorkeeper/oauth/id_token_token_response'
+
+require 'doorkeeper/openid_connect/claims_builder'
+require 'doorkeeper/openid_connect/claims/claim'
+require 'doorkeeper/openid_connect/claims/normal_claim'
+require 'doorkeeper/openid_connect/config'
+require 'doorkeeper/openid_connect/engine'
+require 'doorkeeper/openid_connect/errors'
+require 'doorkeeper/openid_connect/id_token'
+require 'doorkeeper/openid_connect/id_token_token'
+require 'doorkeeper/openid_connect/user_info'
+require 'doorkeeper/openid_connect/version'
+
+require 'doorkeeper/openid_connect/helpers/controller'
+
+require 'doorkeeper/openid_connect/oauth/authorization/code'
+require 'doorkeeper/openid_connect/oauth/authorization_code_request'
+require 'doorkeeper/openid_connect/oauth/password_access_token_request'
+require 'doorkeeper/openid_connect/oauth/pre_authorization'
+require 'doorkeeper/openid_connect/oauth/token_response'
+
+require 'doorkeeper/openid_connect/orm/active_record'
+
+require 'doorkeeper/openid_connect/rails/routes'
+
+module Doorkeeper
+  module OpenidConnect
+    def self.signing_algorithm
+      configuration.signing_algorithm.to_s.upcase.to_sym
+    end
+
+    def self.signing_key
+      key =
+        if %i[HS256 HS384 HS512].include?(signing_algorithm)
+          configuration.signing_key
+        else
+          OpenSSL::PKey.read(configuration.signing_key)
+        end
+      ::JWT::JWK.new(key, { kid_generator: ::JWT::JWK::Thumbprint })
+    end
+
+    def self.signing_key_normalized
+      signing_key.export
+    end
+
+    Doorkeeper::GrantFlow.register(
+      :id_token,
+      response_type_matches: 'id_token',
+      response_mode_matches: %w[fragment form_post],
+      response_type_strategy: Doorkeeper::Request::IdToken,
+    )
+
+    Doorkeeper::GrantFlow.register(
+      'id_token token',
+      response_type_matches: 'id_token token',
+      response_mode_matches: %w[fragment form_post],
+      response_type_strategy: Doorkeeper::Request::IdTokenToken,
+    )
+
+    Doorkeeper::GrantFlow.register_alias(
+      'implicit_oidc', as: ['implicit', 'id_token', 'id_token token']
+    )
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb
new file mode 100644
index 0000000000000000000000000000000000000000..98732f49a22a6e942fdebbe82a81865aa30b6e01
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Claims
+      class AggregatedClaim < Claim
+        attr_accessor :jwt
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/claim.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a0cfa8d4f66126508c26971280ff09de9cd2afaa
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/claim.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Claims
+      class Claim
+        attr_accessor :name, :response, :scope
+
+        # http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
+        # http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
+        STANDARD_CLAIMS = {
+          profile: %i[
+            name family_name given_name middle_name nickname preferred_username
+            profile picture website gender birthdate zoneinfo locale updated_at
+          ],
+          email: %i[email email_verified],
+          address: %i[address],
+          phone: %i[phone_number phone_number_verified],
+        }.freeze
+
+        def initialize(options = {})
+          @name = options[:name].to_sym
+          @response = Array.wrap(options[:response])
+          @scope = options[:scope].to_sym if options[:scope]
+
+          # use default scope for Standard Claims
+          @scope ||= STANDARD_CLAIMS.find do |_scope, claims|
+            claims.include? @name
+          end.try(:first)
+
+          # use profile scope as default fallback
+          @scope ||= :profile
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/distributed_claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/distributed_claim.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3a0d4f874d54e9a9015a9e014dfe3dfd4a740ebd
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/distributed_claim.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Claims
+      class DistributedClaim < Claim
+        attr_accessor :endpoint, :access_token
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/normal_claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/normal_claim.rb
new file mode 100644
index 0000000000000000000000000000000000000000..16b012665518254e5fcdc4c25652dc8322632311
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/normal_claim.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Claims
+      class NormalClaim < Claim
+        attr_reader :generator
+
+        def initialize(options = {})
+          super(options)
+          @generator = options[:generator]
+        end
+
+        def type
+          :normal
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims_builder.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims_builder.rb
new file mode 100644
index 0000000000000000000000000000000000000000..69df8aaaae02e95a240646dc076b632c1966277d
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims_builder.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'ostruct'
+
+module Doorkeeper
+  module OpenidConnect
+    class ClaimsBuilder
+      def self.generate(access_token, response)
+        resource_owner = Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(access_token)
+
+        Doorkeeper::OpenidConnect.configuration.claims.to_h.map do |name, claim|
+          if access_token.scopes.exists?(claim.scope) && claim.response.include?(response)
+            [name, claim.generator.call(resource_owner, access_token.scopes, access_token)]
+          end
+        end.compact.to_h
+      end
+
+      def initialize(&block)
+        @claims = OpenStruct.new
+        instance_eval(&block)
+      end
+
+      def build
+        @claims
+      end
+
+      def normal_claim(name, response: [:user_info], scope: nil, &block)
+        @claims[name] =
+          Claims::NormalClaim.new(
+            name: name,
+            response: response,
+            scope: scope,
+            generator: block
+          )
+      end
+      alias claim normal_claim
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/config.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/config.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6ebce486d238f86369408f45309bf48bd6e5105c
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/config.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    def self.configure(&block)
+      if Doorkeeper.configuration.orm != :active_record
+        raise Errors::InvalidConfiguration, 'Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter'
+      end
+
+      @config = Config::Builder.new(&block).build
+    end
+
+    def self.configuration
+      @config || (raise Errors::MissingConfiguration)
+    end
+
+    class Config
+      class Builder
+        def initialize(&block)
+          @config = Config.new
+          instance_eval(&block)
+        end
+
+        def build
+          @config
+        end
+
+        def jws_public_key(*_args)
+          puts 'DEPRECATION WARNING: `jws_public_key` is not needed anymore and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb'
+        end
+
+        def jws_private_key(*args)
+          puts 'DEPRECATION WARNING: `jws_private_key` has been replaced by `signing_key` and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb'
+          signing_key(*args)
+        end
+      end
+
+      mattr_reader(:builder_class) { Config::Builder }
+
+      extend ::Doorkeeper::Config::Option
+
+      option :issuer
+      option :signing_key
+      option :signing_algorithm, default: :rs256
+      option :subject_types_supported, default: [:public]
+
+      option :resource_owner_from_access_token, default: lambda { |*_|
+        raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.resource_owner_from_access_token_not_configured')
+      }
+
+      option :auth_time_from_resource_owner, default: lambda { |*_|
+        raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.auth_time_from_resource_owner_not_configured')
+      }
+
+      option :reauthenticate_resource_owner, default: lambda { |*_|
+        raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.reauthenticate_resource_owner_not_configured')
+      }
+
+      option :select_account_for_resource_owner, default: lambda { |*_|
+        raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.select_account_for_resource_owner_not_configured')
+      }
+
+      option :subject, default: lambda { |*_|
+        raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.subject_not_configured')
+      }
+
+      option :expiration, default: 120
+
+      option :claims, builder_class: ClaimsBuilder
+
+      option :protocol, default: lambda { |*_|
+        ::Rails.env.production? ? :https : :http
+      }
+
+      option :end_session_endpoint, default: lambda { |*_|
+        nil
+      }
+
+      option :discovery_url_options, default: lambda { |*_|
+        {}
+      }
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/engine.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/engine.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6eb5e3ea0965c0f0f3f9565acf6e049a9ff91432
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/engine.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class Engine < ::Rails::Engine
+      initializer 'doorkeeper.openid_connect.routes' do
+        Doorkeeper::OpenidConnect::Rails::Routes.install!
+      end
+
+      config.to_prepare do
+        Doorkeeper::AuthorizationsController.prepend Doorkeeper::OpenidConnect::AuthorizationsExtension
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/errors.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/errors.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ca7823b24a02a3ead739eeeb3f5e4f350155b244
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/errors.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Errors
+      class OpenidConnectError < StandardError
+        def type
+          self.class.name.demodulize.underscore.to_sym
+        end
+      end
+
+      # internal errors
+      class InvalidConfiguration < OpenidConnectError; end
+      class MissingConfiguration < OpenidConnectError
+        def initialize
+          super('Configuration for Doorkeeper OpenID Connect missing. Do you have doorkeeper_openid_connect initializer?')
+        end
+      end
+
+      # OAuth 2.0 errors
+      # https://tools.ietf.org/html/rfc6749#section-4.1.2.1
+      class InvalidRequest < OpenidConnectError; end
+
+      # OpenID Connect 1.0 errors
+      # http://openid.net/specs/openid-connect-core-1_0.html#AuthError
+      class LoginRequired < OpenidConnectError; end
+      class ConsentRequired < OpenidConnectError; end
+      class InteractionRequired < OpenidConnectError; end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/helpers/controller.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/helpers/controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d3e8396120a041fb9c1758b3f3ce111e16c35069
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/helpers/controller.rb
@@ -0,0 +1,141 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Helpers
+      module Controller
+        private
+
+        # FIXME: remove after Doorkeeper will merge it
+        def current_resource_owner
+          return @current_resource_owner if defined?(@current_resource_owner)
+
+          super
+        end
+
+        def authenticate_resource_owner!
+          super.tap do |owner|
+            next unless oidc_authorization_request?
+
+            handle_oidc_prompt_param!(owner)
+            handle_oidc_max_age_param!(owner)
+          end
+        rescue Errors::OpenidConnectError => e
+          handle_oidc_error!(e)
+        end
+
+        def oidc_authorization_request?
+          controller_path == Doorkeeper::Rails::Routes.mapping[:authorizations][:controllers] &&
+            action_name == 'new' &&
+            pre_auth.valid? &&
+            pre_auth.scopes.include?('openid')
+        end
+
+        def handle_oidc_error!(exception)
+          # clear the previous response body to avoid a DoubleRenderError
+          self.response_body = nil
+
+          # FIXME: workaround for Rails 5, see https://github.com/rails/rails/issues/25106
+          @_response_body = nil
+
+          error_response = if exception.type == :invalid_request
+                             ::Doorkeeper::OAuth::InvalidRequestResponse.new(
+                               name: exception.type,
+                               state: params[:state],
+                               redirect_uri: params[:redirect_uri],
+                               response_on_fragment: pre_auth.response_on_fragment?,
+                             )
+                           else
+                             ::Doorkeeper::OAuth::ErrorResponse.new(
+                               name: exception.type,
+                               state: params[:state],
+                               redirect_uri: params[:redirect_uri],
+                               response_on_fragment: pre_auth.response_on_fragment?,
+                             )
+                           end
+
+          response.headers.merge!(error_response.headers)
+
+          # NOTE: Assign error_response to @authorize_response then use redirect_or_render method that are defined at
+          #   doorkeeper's authorizations_controller.
+          # - https://github.com/doorkeeper-gem/doorkeeper/blob/v5.5.0/app/controllers/doorkeeper/authorizations_controller.rb#L110
+          # - https://github.com/doorkeeper-gem/doorkeeper/blob/v5.5.0/app/controllers/doorkeeper/authorizations_controller.rb#L52
+          @authorize_response = error_response
+          redirect_or_render(@authorize_response)
+        end
+
+        def handle_oidc_prompt_param!(owner)
+          prompt_values ||= params[:prompt].to_s.split(/ +/).uniq
+
+          prompt_values.each do |prompt|
+            case prompt
+            when 'none'
+              raise Errors::InvalidRequest if (prompt_values - ['none']).any?
+              raise Errors::LoginRequired unless owner
+              raise Errors::ConsentRequired if oidc_consent_required?
+            when 'login'
+              reauthenticate_oidc_resource_owner(owner) if owner
+            when 'consent'
+              render :new if owner
+            when 'select_account'
+              select_account_for_oidc_resource_owner(owner)
+            else
+              raise Errors::InvalidRequest
+            end
+          end
+        end
+
+        def handle_oidc_max_age_param!(owner)
+          max_age = params[:max_age].to_i
+          return unless max_age > 0 && owner
+
+          auth_time = instance_exec(
+            owner,
+            &Doorkeeper::OpenidConnect.configuration.auth_time_from_resource_owner
+          )
+
+          if !auth_time || (Time.zone.now - auth_time) > max_age
+            reauthenticate_oidc_resource_owner(owner)
+          end
+        end
+
+        def return_without_oidc_prompt_param(prompt_value)
+          return_to = URI.parse(request.path)
+          return_to.query = request.query_parameters.tap do |params|
+            params['prompt'] = params['prompt'].to_s.sub(/\b#{prompt_value}\s*\b/, '').strip
+            params.delete('prompt') if params['prompt'].blank?
+          end.to_query
+          return_to.to_s
+        end
+
+        def reauthenticate_oidc_resource_owner(owner)
+          return_to = return_without_oidc_prompt_param('login')
+
+          instance_exec(
+            owner,
+            return_to,
+            &Doorkeeper::OpenidConnect.configuration.reauthenticate_resource_owner
+          )
+
+          raise Errors::LoginRequired unless performed?
+        end
+
+        def oidc_consent_required?
+          !skip_authorization? && !matching_token?
+        end
+
+        def select_account_for_oidc_resource_owner(owner)
+          return_to = return_without_oidc_prompt_param('select_account')
+
+          instance_exec(
+            owner,
+            return_to,
+            &Doorkeeper::OpenidConnect.configuration.select_account_for_resource_owner
+          )
+        end
+      end
+    end
+  end
+
+  Helpers::Controller.prepend OpenidConnect::Helpers::Controller
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token.rb
new file mode 100644
index 0000000000000000000000000000000000000000..69dfb0c92bb5582f500e649fd19e85fec1dfee02
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class IdToken
+      include ActiveModel::Validations
+
+      attr_reader :nonce
+
+      def initialize(access_token, nonce = nil)
+        @access_token = access_token
+        @nonce = nonce
+        @resource_owner = Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(access_token)
+        @issued_at = Time.zone.now
+      end
+
+      def claims
+        {
+          iss: issuer,
+          sub: subject,
+          aud: audience,
+          exp: expiration,
+          iat: issued_at,
+          nonce: nonce,
+          auth_time: auth_time
+        }.merge ClaimsBuilder.generate(@access_token, :id_token)
+      end
+
+      def as_json(*_)
+        claims.reject { |_, value| value.nil? || value == '' }
+      end
+
+      def as_jws_token
+        ::JWT.encode(as_json,
+          Doorkeeper::OpenidConnect.signing_key.keypair,
+          Doorkeeper::OpenidConnect.signing_algorithm.to_s,
+          { typ: 'JWT', kid: Doorkeeper::OpenidConnect.signing_key.kid }
+        ).to_s
+      end
+
+      private
+
+      def issuer
+        if Doorkeeper::OpenidConnect.configuration.issuer.respond_to?(:call)
+          Doorkeeper::OpenidConnect.configuration.issuer.call(@resource_owner, @access_token.application).to_s
+        else
+          Doorkeeper::OpenidConnect.configuration.issuer
+        end
+      end
+
+      def subject
+        Doorkeeper::OpenidConnect.configuration.subject.call(@resource_owner, @access_token.application).to_s
+      end
+
+      def audience
+        @access_token.application.try(:uid)
+      end
+
+      def expiration
+        (@issued_at.utc + Doorkeeper::OpenidConnect.configuration.expiration).to_i
+      end
+
+      def issued_at
+        @issued_at.utc.to_i
+      end
+
+      def auth_time
+        Doorkeeper::OpenidConnect.configuration.auth_time_from_resource_owner.call(@resource_owner).try(:to_i)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token_token.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6e78fea88cd297b30f282eb05279532784d3e77c
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token_token.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class IdTokenToken < IdToken
+      def claims
+        super.merge(at_hash: at_hash)
+      end
+
+      private
+
+      # The at_hash is build according to the following standard:
+      #
+      # http://openid.net/specs/openid-connect-implicit-1_0.html#IDToken
+      #
+      # at_hash:
+      #   REQUIRED. Access Token hash value. If the ID Token is issued with an
+      #   access_token in an Implicit Flow, this is REQUIRED, which is the case
+      #   for this subset of OpenID Connect. Its value is the base64url encoding
+      #   of the left-most half of the hash of the octets of the ASCII
+      #   representation of the access_token value, where the hash algorithm
+      #   used is the hash algorithm used in the alg Header Parameter of the
+      #   ID Token's JOSE Header. For instance, if the alg is RS256, hash the
+      #   access_token value with SHA-256, then take the left-most 128 bits and
+      #   base64url-encode them. The at_hash value is a case-sensitive string.
+      def at_hash
+        sha256 = Digest::SHA256.new
+        token = @access_token.token
+        hashed_token = sha256.digest(token)
+        first_half = hashed_token[0...hashed_token.length / 2]
+        Base64.urlsafe_encode64(first_half).tr('=', '')
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization/code.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization/code.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f04bb0412ac90199f71b9faeb8f53d6b383d2367
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization/code.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module OAuth
+      module Authorization
+        module Code
+          if Doorkeeper::OAuth::Authorization::Code.method_defined?(:issue_token!)
+            def issue_token!
+              super.tap do |access_grant|
+                create_openid_request(access_grant) if pre_auth.nonce.present?
+              end
+            end
+
+            alias issue_token issue_token!
+          else
+            # FIXME: drop this after dropping support of Doorkeeper < 5.4
+            def issue_token
+              super.tap do |access_grant|
+                create_openid_request(access_grant) if pre_auth.nonce.present?
+              end
+            end
+          end
+
+          private
+
+          def create_openid_request(access_grant)
+            ::Doorkeeper::OpenidConnect::Request.create!(
+              access_grant: access_grant,
+              nonce: pre_auth.nonce
+            )
+          end
+        end
+      end
+    end
+  end
+
+  OAuth::Authorization::Code.prepend OpenidConnect::OAuth::Authorization::Code
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1044d6638507187ca5dd298903ad169a6a5797d8
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module OAuth
+      module AuthorizationCodeRequest
+        private
+
+        def after_successful_response
+          super
+
+          nonce =
+            if (openid_request = grant.openid_request)
+              openid_request.destroy!
+              openid_request.nonce
+            end
+
+          id_token = Doorkeeper::OpenidConnect::IdToken.new(access_token, nonce)
+          @response.id_token = id_token
+        end
+      end
+    end
+  end
+
+  OAuth::AuthorizationCodeRequest.prepend OpenidConnect::OAuth::AuthorizationCodeRequest
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9e00f639ad89e1bdfe9a0c6d1a4827465fecaeaa
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module OAuth
+      module PasswordAccessTokenRequest
+        attr_reader :nonce
+
+        if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.1')
+          def initialize(server, client, credentials, resource_owner, parameters = {})
+            super
+            @nonce = parameters[:nonce]
+          end
+        else
+          def initialize(server, client, resource_owner, parameters = {})
+            super
+            @nonce = parameters[:nonce]
+          end
+        end
+
+        private
+
+        def after_successful_response
+          id_token = Doorkeeper::OpenidConnect::IdToken.new(access_token, nonce)
+          @response.id_token = id_token
+          super
+        end
+      end
+    end
+  end
+
+  OAuth::PasswordAccessTokenRequest.prepend OpenidConnect::OAuth::PasswordAccessTokenRequest
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb
new file mode 100644
index 0000000000000000000000000000000000000000..231f065a26836af46cf8503701f7d3f4a2012e98
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module OAuth
+      module PreAuthorization
+        attr_reader :nonce
+
+        def initialize(server, attrs = {}, resource_owner = nil)
+          super
+          @nonce = attrs[:nonce]
+        end
+
+        # NOTE: Auto get default response_mode of specified response_type if response_mode is not
+        #   yet present. We can delete this method after Doorkeeper's minimize version support it.
+        def response_on_fragment?
+          return response_mode == 'fragment' if response_mode.present?
+
+          grant_flow = server.authorization_response_flows.detect do |flow|
+            flow.matches_response_type?(response_type)
+          end
+
+          grant_flow&.default_response_mode == 'fragment'
+        end
+      end
+    end
+  end
+
+  OAuth::PreAuthorization.prepend OpenidConnect::OAuth::PreAuthorization
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/token_response.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/token_response.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9aa3c4139619dc218454b6b08b4b493e8bcb017d
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/token_response.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module OAuth
+      module TokenResponse
+        attr_accessor :id_token
+
+        def body
+          if token.includes_scope? 'openid'
+            id_token = self.id_token || Doorkeeper::OpenidConnect::IdToken.new(token)
+
+            super
+              .merge(id_token: id_token.as_jws_token)
+              .reject { |_, value| value.blank? }
+          else
+            super
+          end
+        end
+      end
+    end
+  end
+
+  OAuth::TokenResponse.prepend OpenidConnect::OAuth::TokenResponse
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e9005ab6ed946db5bdfc685a63a5516baaa4923a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'active_support/lazy_load_hooks'
+
+module Doorkeeper
+  module OpenidConnect
+    autoload :AccessGrant, "doorkeeper/openid_connect/orm/active_record/access_grant"
+    autoload :Request, "doorkeeper/openid_connect/orm/active_record/request"
+
+    module Orm
+      module ActiveRecord
+        def run_hooks
+          super
+
+          if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.0')
+            Doorkeeper.config.access_grant_model.prepend Doorkeeper::OpenidConnect::AccessGrant
+          else
+            Doorkeeper::AccessGrant.prepend Doorkeeper::OpenidConnect::AccessGrant
+          end
+
+          if Doorkeeper.configuration.respond_to?(:active_record_options) && Doorkeeper.configuration.active_record_options[:establish_connection]
+            [Doorkeeper::OpenidConnect::Request].each do |c|
+              c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection]
+            end
+          end
+        end
+
+        def initialize_models!
+          super
+          ActiveSupport.on_load(:active_record) do
+            require 'doorkeeper/openid_connect/orm/active_record/access_grant'
+            require 'doorkeeper/openid_connect/orm/active_record/request'
+
+            if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.0')
+              Doorkeeper.config.access_grant_model.prepend Doorkeeper::OpenidConnect::AccessGrant
+            else
+              Doorkeeper::AccessGrant.prepend Doorkeeper::OpenidConnect::AccessGrant
+            end
+
+            if Doorkeeper.configuration.active_record_options[:establish_connection]
+              [Doorkeeper::OpenidConnect::Request].each do |c|
+                c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection]
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+
+  Orm::ActiveRecord.singleton_class.send :prepend, OpenidConnect::Orm::ActiveRecord
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3e51f45e63dd55d176028de98b2002d0aef11ffc
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module AccessGrant
+      def self.prepended(base)
+        base.class_eval do
+          has_one :openid_request,
+            class_name: 'Doorkeeper::OpenidConnect::Request',
+            foreign_key: 'access_grant_id',
+            inverse_of: :access_grant,
+            dependent: :delete
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/request.rb
new file mode 100644
index 0000000000000000000000000000000000000000..009ba7bd752d76c3a1864f9ebff7eaf9d93ff9e2
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/request.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class Request < ::ActiveRecord::Base
+      self.table_name = "#{table_name_prefix}oauth_openid_requests#{table_name_suffix}".to_sym
+
+      validates :access_grant_id, :nonce, presence: true
+
+      if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.0')
+        belongs_to :access_grant,
+                   class_name: Doorkeeper.config.access_grant_class.to_s,
+                   inverse_of: :openid_request
+      else
+        belongs_to :access_grant,
+                   class_name: 'Doorkeeper::AccessGrant',
+                   inverse_of: :openid_request
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2a44c27f6164a883649d417a09dc0ff15fb4f804
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'doorkeeper/openid_connect/rails/routes/mapping'
+require 'doorkeeper/openid_connect/rails/routes/mapper'
+
+module Doorkeeper
+  module OpenidConnect
+    module Rails
+      class Routes
+        module Helper
+          def use_doorkeeper_openid_connect(options = {}, &block)
+            Doorkeeper::OpenidConnect::Rails::Routes.new(self, &block).generate_routes!(options)
+          end
+        end
+
+        def self.install!
+          ActionDispatch::Routing::Mapper.include Doorkeeper::OpenidConnect::Rails::Routes::Helper
+        end
+
+        attr_accessor :routes
+
+        def initialize(routes, &block)
+          @routes = routes
+          @block = block
+        end
+
+        def generate_routes!(options)
+          @mapping = Mapper.new.map(&@block)
+          routes.scope options[:scope] || 'oauth', as: 'oauth' do
+            map_route(:userinfo, :userinfo_routes)
+            map_route(:discovery, :discovery_routes)
+          end
+
+          routes.scope as: 'oauth' do
+            map_route(:discovery, :discovery_well_known_routes)
+          end
+        end
+
+        private
+
+        def map_route(name, method)
+          return if @mapping.skipped?(name)
+
+          mapping = @mapping[name]
+
+          routes.scope controller: mapping[:controllers], as: mapping[:as] do
+            send method
+          end
+        end
+
+        def userinfo_routes
+          routes.get :show, path: 'userinfo', as: ''
+          routes.post :show, path: 'userinfo', as: nil
+        end
+
+        def discovery_routes
+          routes.scope path: 'discovery' do
+            routes.get :keys
+          end
+        end
+
+        def discovery_well_known_routes
+          routes.scope path: '.well-known' do
+            routes.get :provider, path: 'openid-configuration'
+            routes.get :provider, path: 'oauth-authorization-server'
+            routes.get :webfinger
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapper.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1931edcc7f0f4b67dfd0b472bf14e31d0194f9bd
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapper.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Rails
+      class Routes
+        class Mapper
+          def initialize(mapping = Mapping.new)
+            @mapping = mapping
+          end
+
+          def map(&block)
+            instance_eval(&block) if block
+            @mapping
+          end
+
+          def controllers(controller_names = {})
+            @mapping.controllers.merge!(controller_names)
+          end
+
+          def skip_controllers(*controller_names)
+            @mapping.skips = controller_names
+          end
+
+          def as(alias_names = {})
+            @mapping.as.merge!(alias_names)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapping.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapping.rb
new file mode 100644
index 0000000000000000000000000000000000000000..307f4045017dc171a770bc85d2cae65a8abc5002
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapping.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    module Rails
+      class Routes
+        class Mapping
+          attr_accessor :controllers, :as, :skips
+
+          def initialize
+            @controllers = {
+              userinfo: 'doorkeeper/openid_connect/userinfo',
+              discovery: 'doorkeeper/openid_connect/discovery'
+            }
+
+            @as = {
+              userinfo: :userinfo,
+              discovery: :discovery
+            }
+
+            @skips = []
+          end
+
+          def [](routes)
+            {
+              controllers: @controllers[routes],
+              as: @as[routes]
+            }
+          end
+
+          def skipped?(controller)
+            @skips.include?(controller)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/user_info.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/user_info.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9b82334c111ecb0a9fff00ccd477a4c748ce7941
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/user_info.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class UserInfo
+      include ActiveModel::Validations
+
+      def initialize(access_token)
+        @access_token = access_token
+      end
+
+      def claims
+        {
+          sub: subject
+        }.merge ClaimsBuilder.generate(@access_token, :user_info)
+      end
+
+      def as_json(*_)
+        claims.reject { |_, value| value.nil? || value == '' }
+      end
+
+      private
+
+      def subject
+        Doorkeeper::OpenidConnect.configuration.subject.call(resource_owner, application).to_s
+      end
+
+      def resource_owner
+        @resource_owner ||= Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(@access_token)
+      end
+
+      def application
+        @application ||= @access_token.application
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/version.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/version.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4a17095e367f50cc7f81d6ac0056d46d1cd3f4c0
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/version.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    VERSION = '1.8.9'
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1c6967001ac257b9a304f93edf6925d3fd388b65
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'doorkeeper/request/strategy'
+
+module Doorkeeper
+  module Request
+    class IdToken < Strategy
+      delegate :current_resource_owner, to: :server
+
+      def pre_auth
+        server.context.send(:pre_auth)
+      end
+
+      def request
+        @request ||= OAuth::IdTokenRequest.new(pre_auth, current_resource_owner)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token_token.rb
new file mode 100644
index 0000000000000000000000000000000000000000..100d6a18f1ed99800b85e0ad7e999a8edead5d6b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token_token.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'doorkeeper/request/strategy'
+
+module Doorkeeper
+  module Request
+    class IdTokenToken < Strategy
+      delegate :current_resource_owner, to: :server
+
+      def pre_auth
+        server.context.send(:pre_auth)
+      end
+
+      def request
+        @request ||= OAuth::IdTokenTokenRequest.new(pre_auth, current_resource_owner)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/install_generator.rb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/install_generator.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8d3a46693328f2ff23e5d9dd6273575b757ac5b7
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/install_generator.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Doorkeeper
+  module OpenidConnect
+    class InstallGenerator < ::Rails::Generators::Base
+      include ::Rails::Generators::Migration
+      source_root File.expand_path('templates', __dir__)
+      desc 'Installs Doorkeeper OpenID Connect.'
+
+      def install
+        template 'initializer.rb', 'config/initializers/doorkeeper_openid_connect.rb'
+        copy_file File.expand_path('../../../../config/locales/en.yml', __dir__), 'config/locales/doorkeeper_openid_connect.en.yml'
+        route 'use_doorkeeper_openid_connect'
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/migration_generator.rb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/migration_generator.rb
new file mode 100644
index 0000000000000000000000000000000000000000..50fecec6189ddd511733967e797af71c5b1e25de
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/migration_generator.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails/generators/active_record'
+
+module Doorkeeper
+  module OpenidConnect
+    class MigrationGenerator < ::Rails::Generators::Base
+      include ::Rails::Generators::Migration
+      source_root File.expand_path('templates', __dir__)
+      desc 'Installs Doorkeeper OpenID Connect migration file.'
+
+      def install
+        migration_template(
+          'migration.rb.erb',
+          'db/migrate/create_doorkeeper_openid_connect_tables.rb',
+          migration_version: migration_version
+        )
+      end
+
+      def self.next_migration_number(dirname)
+        ActiveRecord::Generators::Base.next_migration_number(dirname)
+      end
+
+      private
+
+      def migration_version
+        if ActiveRecord::VERSION::MAJOR >= 5
+          "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
+        end
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/initializer.rb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/initializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4c322760115abb574035e53d921b5498511355ea
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/initializer.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+Doorkeeper::OpenidConnect.configure do
+  issuer do |resource_owner, application|
+    'issuer string'
+  end
+
+  signing_key <<~KEY
+    -----BEGIN RSA PRIVATE KEY-----
+    ....
+    -----END RSA PRIVATE KEY-----
+  KEY
+
+  subject_types_supported [:public]
+
+  resource_owner_from_access_token do |access_token|
+    # Example implementation:
+    # User.find_by(id: access_token.resource_owner_id)
+  end
+
+  auth_time_from_resource_owner do |resource_owner|
+    # Example implementation:
+    # resource_owner.current_sign_in_at
+  end
+
+  reauthenticate_resource_owner do |resource_owner, return_to|
+    # Example implementation:
+    # store_location_for resource_owner, return_to
+    # sign_out resource_owner
+    # redirect_to new_user_session_url
+  end
+
+  # Depending on your configuration, a DoubleRenderError could be raised
+  # if render/redirect_to is called at some point before this callback is executed.
+  # To avoid the DoubleRenderError, you could add these two lines at the beginning
+  #  of this callback: (Reference: https://github.com/rails/rails/issues/25106)
+  #   self.response_body = nil
+  #   @_response_body = nil
+  select_account_for_resource_owner do |resource_owner, return_to|
+    # Example implementation:
+    # store_location_for resource_owner, return_to
+    # redirect_to account_select_url
+  end
+
+  subject do |resource_owner, application|
+    # Example implementation:
+    # resource_owner.id
+
+    # or if you need pairwise subject identifier, implement like below:
+    # Digest::SHA256.hexdigest("#{resource_owner.id}#{URI.parse(application.redirect_uri).host}#{'your_secret_salt'}")
+  end
+
+  # Protocol to use when generating URIs for the discovery endpoint,
+  # for example if you also use HTTPS in development
+  # protocol do
+  #   :https
+  # end
+
+  # Expiration time on or after which the ID Token MUST NOT be accepted for processing. (default 120 seconds).
+  # expiration 600
+
+  # Example claims:
+  # claims do
+  #   normal_claim :_foo_ do |resource_owner|
+  #     resource_owner.foo
+  #   end
+
+  #   normal_claim :_bar_ do |resource_owner|
+  #     resource_owner.bar
+  #   end
+  # end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb
new file mode 100644
index 0000000000000000000000000000000000000000..05dac3eece5049cc2cc901693c4ea84627f094f1
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb
@@ -0,0 +1,15 @@
+class CreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration<%= migration_version %>
+  def change
+    create_table :oauth_openid_requests do |t|
+      t.references :access_grant, null: false, index: true
+      t.string :nonce, null: false
+    end
+
+    add_foreign_key(
+      :oauth_openid_requests,
+      :oauth_access_grants,
+      column: :access_grant_id,
+      on_delete: :cascade
+    )
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/discovery_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/discovery_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..68a0341275da328af5eb6f45e5ddbfe76794f65f
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/discovery_controller_spec.rb
@@ -0,0 +1,316 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::DiscoveryController, type: :controller do
+  describe '#provider' do
+    it 'returns the provider configuration' do
+      get :provider
+      data = JSON.parse(response.body)
+
+      expect(data.sort).to match({
+        'issuer' => 'dummy',
+        'authorization_endpoint' => 'http://test.host/oauth/authorize',
+        'token_endpoint' => 'http://test.host/oauth/token',
+        'revocation_endpoint' => 'http://test.host/oauth/revoke',
+        'introspection_endpoint' => 'http://test.host/oauth/introspect',
+        'userinfo_endpoint' => 'http://test.host/oauth/userinfo',
+        'jwks_uri' => 'http://test.host/oauth/discovery/keys',
+
+        'scopes_supported' => ['openid'],
+        'response_types_supported' => ['code', 'token', 'id_token', 'id_token token'],
+        'response_modes_supported' => %w[query fragment form_post],
+        'grant_types_supported' => %w[authorization_code client_credentials implicit_oidc],
+
+        'token_endpoint_auth_methods_supported' => %w[client_secret_basic client_secret_post],
+
+        'subject_types_supported' => [
+          'public',
+        ],
+
+        'id_token_signing_alg_values_supported' => [
+          'RS256',
+        ],
+
+        'claim_types_supported' => [
+          'normal',
+        ],
+
+        'claims_supported' => %w[
+          iss
+          sub
+          aud
+          exp
+          iat
+          name
+          variable_name
+          created_at
+          updated_at
+          token_id
+          both_responses
+          id_token_response
+          user_info_response
+        ],
+
+        'code_challenge_methods_supported' => %w[
+          plain
+          S256
+        ],
+      }.sort)
+    end
+
+    context 'when refresh_token grant type is enabled' do
+      before { Doorkeeper.configure { use_refresh_token } }
+
+      it 'add refresh_token to grant_types_supported' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['grant_types_supported']).to eq %w[authorization_code client_credentials refresh_token]
+      end
+    end
+
+    context 'when issuer block' do
+      before { Doorkeeper::OpenidConnect.configure { issuer do |r, a| "test-issuer" end } }
+
+      it 'return blocks result' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['issuer']).to eq "test-issuer"
+      end
+    end
+
+    context 'when grant_flows is configed with only client_credentials' do
+      before { Doorkeeper.configure { grant_flows %w[client_credentials] } }
+
+      it 'return empty response_modes_supported' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['response_modes_supported']).to eq []
+      end
+    end
+
+    context 'when grant_flows is configed only implicit flow' do
+      before { Doorkeeper.configure { grant_flows %w[implicit_oidc] } }
+
+      it 'return fragment and form_post as response_modes_supported' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['response_modes_supported']).to eq %w[fragment form_post]
+      end
+    end
+
+    context 'when grant_flows is configed with authorization_code and implicit flow' do
+      before { Doorkeeper.configure { grant_flows %w[authorization_code implicit_oidc] } }
+
+      it 'return query, fragment and form_post as response_modes_supported' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['response_modes_supported']).to eq %w[query fragment form_post]
+      end
+    end
+
+    it 'uses the protocol option for generating URLs' do
+      Doorkeeper::OpenidConnect.configure do
+        protocol { :testing }
+      end
+
+      get :provider
+      data = JSON.parse(response.body)
+
+      expect(data['authorization_endpoint']).to eq 'testing://test.host/oauth/authorize'
+    end
+
+    context 'when the discovery_url_options option is set for all endpoints' do
+      before do
+        Doorkeeper::OpenidConnect.configure do
+          discovery_url_options do |request|
+            {
+              authorization: { host: 'alternate-authorization.host' },
+              token: { host: 'alternate-token.host' },
+              revocation: { host: 'alternate-revocation.host' },
+              introspection: { host: 'alternate-introspection.host' },
+              userinfo: { host: 'alternate-userinfo.host' },
+              jwks: { host: 'alternate-jwks.host' }
+            }
+          end
+        end
+      end
+
+      it 'uses the discovery_url_options option when generating the endpoint urls' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['authorization_endpoint']).to eq 'http://alternate-authorization.host/oauth/authorize'
+        expect(data['token_endpoint']).to eq 'http://alternate-token.host/oauth/token'
+        expect(data['revocation_endpoint']).to eq 'http://alternate-revocation.host/oauth/revoke'
+        expect(data['introspection_endpoint']).to eq 'http://alternate-introspection.host/oauth/introspect'
+        expect(data['userinfo_endpoint']).to eq 'http://alternate-userinfo.host/oauth/userinfo'
+        expect(data['jwks_uri']).to eq 'http://alternate-jwks.host/oauth/discovery/keys'
+      end
+    end
+
+    context 'when the discovery_url_options option is only set for some endpoints' do
+      before do
+        Doorkeeper::OpenidConnect.configure do
+          discovery_url_options do |request|
+            { authorization: { host: 'alternate-authorization.host' } }
+          end
+        end
+      end
+
+      it 'does not use the discovery_url_options option when generating other URLs' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        {
+          'token_endpoint' => 'http://test.host/oauth/token',
+          'revocation_endpoint' => 'http://test.host/oauth/revoke',
+          'introspection_endpoint' => 'http://test.host/oauth/introspect',
+          'userinfo_endpoint' => 'http://test.host/oauth/userinfo',
+          'jwks_uri' => 'http://test.host/oauth/discovery/keys',
+        }.each do |endpoint, expected_url|
+          expect(data[endpoint]).to eq expected_url
+        end
+      end
+    end
+
+    it 'does not return an end session endpoint if none is configured' do
+      get :provider
+      data = JSON.parse(response.body)
+
+      expect(data.key?('end_session_endpoint')).to be(false)
+    end
+
+    it 'uses the configured end session endpoint with self as context' do
+      Doorkeeper::OpenidConnect.configure do
+        end_session_endpoint -> { logout_url }
+      end
+
+      def controller.logout_url
+        'http://test.host/logout'
+      end
+
+      get :provider
+      data = JSON.parse(response.body)
+
+      expect(data['end_session_endpoint']).to eq 'http://test.host/logout'
+    end
+
+    context 'when token inspection is disallowed' do
+      let(:doorkeeper_config) { Doorkeeper.config }
+      let!(:allow_token_introspection) { doorkeeper_config.allow_token_introspection }
+
+      before do
+        allow(doorkeeper_config).to receive(:allow_token_introspection).and_return(false)
+        Rails.application.reload_routes!
+      end
+
+      after do
+        allow(doorkeeper_config).to receive(:allow_token_introspection).and_return(allow_token_introspection)
+        Rails.application.reload_routes!
+      end
+
+      it 'does not return introspection_endpoint' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data.key?('introspection_endpoint')).to be(false)
+      end
+    end
+  end
+
+  describe '#webfinger' do
+    it 'requires the resource parameter' do
+      expect do
+        get :webfinger
+      end.to raise_error ActionController::ParameterMissing
+    end
+
+    it 'returns the OpenID Connect relation' do
+      get :webfinger, params: { resource: 'user@example.com' }
+      data = JSON.parse(response.body)
+
+      expect(data.sort).to eq({
+        'subject' => 'user@example.com',
+        'links' => [
+          'rel' => 'http://openid.net/specs/connect/1.0/issuer',
+          'href' => 'http://test.host/',
+        ],
+      }.sort)
+    end
+
+    context 'when the discovery_url_options option is set for webfinger endpoint' do
+      before do
+        Doorkeeper::OpenidConnect.configure do
+          discovery_url_options do |request|
+            { webfinger: { host: 'alternate-webfinger.host' } }
+          end
+        end
+      end
+
+      it 'uses the discovery_url_options option when generating the webfinger endpoint url' do
+        get :webfinger, params: { resource: 'user@example.com' }
+        data = JSON.parse(response.body)
+
+        expect(data['links'].first['href']).to eq 'http://alternate-webfinger.host/'
+      end
+    end
+
+    context 'when the discovery_url_options option uses the request for an endpoint' do
+      before do
+        Doorkeeper::OpenidConnect.configure do
+          discovery_url_options do |request|
+            {
+              authorization: { host: 'alternate-authorization.host',
+                               protocol: request.ssl? ? :https : :testing }
+            }
+          end
+        end
+      end
+
+      it 'uses the discovery_url_options option when generating the webfinger endpoint url' do
+        get :provider
+        data = JSON.parse(response.body)
+
+        expect(data['authorization_endpoint']).to eq 'testing://alternate-authorization.host/oauth/authorize'
+      end
+    end
+  end
+
+  describe '#keys' do
+    subject { get :keys }
+
+    shared_examples 'a key response' do |options|
+      expected_parameters = options[:expected_parameters]
+
+      it "includes only #{expected_parameters.join(', ')} parameters" do
+        subject
+        data = JSON.parse(response.body)
+        key = data['keys'].first
+
+        expect(key.keys.map(&:to_sym)).to match_array(expected_parameters)
+      end
+    end
+
+    context 'when using an RSA key' do
+      it_behaves_like 'a key response', expected_parameters: %i[kty kid e n use alg]
+    end
+
+    context 'when using an EC key' do
+      before { configure_ec }
+
+      it_behaves_like 'a key response', expected_parameters: %i[kty kid crv x y use alg]
+    end
+
+    context 'when using an HMAC key' do
+      before { configure_hmac }
+
+      it_behaves_like 'a key response', expected_parameters: %i[kty kid use alg]
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorizations_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorizations_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7f1da7da590a94a983126d31f10c851e4b3d86f5
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorizations_controller_spec.rb
@@ -0,0 +1,433 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::AuthorizationsController, type: :controller do
+  let(:user) { create :user }
+  let(:application) { create :application, scopes: default_scopes }
+  let(:default_scopes) { 'openid profile' }
+  let(:token_attributes) { { application_id: application.id, resource_owner_id: user.id, scopes: default_scopes } }
+
+  def authorize!(params = {})
+    get :new, params: {
+      response_type: 'code',
+      response_mode: '',
+      current_user: user.id,
+      client_id: application.uid,
+      scope: default_scopes,
+      redirect_uri: application.redirect_uri,
+    }.merge(params)
+  end
+
+  def build_redirect_uri(params = {}, type: 'query')
+    case type
+    when 'query'
+      Doorkeeper::OAuth::Authorization::URIBuilder.uri_with_query(application.redirect_uri, params)
+    when 'fragment'
+      Doorkeeper::OAuth::Authorization::URIBuilder.uri_with_fragment(application.redirect_uri, params)
+    else
+      raise ArgumentError, "Unsupported uri type #{type}"
+    end
+  end
+
+  def expect_authorization_form!
+    expect(response).to be_successful
+    expect(response).to render_template('doorkeeper/authorizations/new')
+  end
+
+  def expect_successful_callback!
+    expect(response).to be_redirect
+    expect(response.location).to match(/^#{Regexp.quote application.redirect_uri}\?code=[-\w]+$/)
+  end
+
+  describe '#authenticate_resource_owner!' do
+    it 'redirects to login form when not logged in' do
+      authorize! current_user: nil
+
+      expect(response).to redirect_to '/login'
+    end
+
+    context 'with OIDC requests' do
+      before do
+        expect(controller).to receive(:handle_oidc_prompt_param!)
+        expect(controller).to receive(:handle_oidc_max_age_param!)
+      end
+
+      it 'renders the authorization form if logged in' do
+        authorize!
+
+        expect_authorization_form!
+      end
+    end
+
+    context 'with non-OIDC requests' do
+      before do
+        expect(controller).not_to receive(:handle_oidc_prompt_param!)
+        expect(controller).not_to receive(:handle_oidc_max_age_param!)
+      end
+
+      it 'when action is not :new' do
+        get :show, params: {
+          response_type: 'code',
+          current_user: user.id,
+          client_id: application.uid,
+          scope: default_scopes,
+          redirect_uri: application.redirect_uri,
+        }
+
+        expect(response).to render_template('doorkeeper/authorizations/show')
+      end
+
+      context 'when pre_authorization is invalid' do
+        it 'render error when client_id is missing' do
+          authorize!(client_id: nil)
+
+          expect(response).to be_successful
+          expect(response).to render_template('doorkeeper/authorizations/error')
+        end
+
+        it 'render error when response_type is missing' do
+          authorize!(response_type: nil)
+
+          expect(response).to be_successful
+          expect(response).to render_template('doorkeeper/authorizations/error')
+        end
+      end
+
+      it 'when openid scope is not present' do
+        authorize!(scope: 'profile')
+
+        expect_authorization_form!
+      end
+    end
+  end
+
+  describe '#handle_oidc_prompt_param!' do
+    it 'is ignored when the openid scope is not present' do
+      authorize! scope: 'profile', prompt: 'invalid'
+
+      expect_authorization_form!
+    end
+
+    context 'with a prompt=none parameter' do
+      context 'and a matching token' do
+        before do
+          create :access_token, token_attributes
+        end
+
+        it 'redirects to the callback if logged in' do
+          authorize! prompt: 'none'
+
+          expect_successful_callback!
+        end
+
+        context 'when another prompt value is present' do
+          let(:error_params) do
+            {
+              'error' => 'invalid_request',
+              'error_description' => 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.',
+            }
+          end
+          let(:request_param) { { prompt: 'none login' } }
+
+          it 'redirect as the query uri with an invalid_request error' do
+            authorize! request_param
+
+            expect(response).to redirect_to build_redirect_uri(error_params)
+          end
+
+          it 'redirect as the fragment style uri when response_type is implicit flow request' do
+            allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+            authorize! request_param.merge(response_type: 'id_token token')
+
+            expect(response).to redirect_to build_redirect_uri(error_params, type: 'fragment')
+          end
+
+          it 'set @authorize_response variable and render form_post template and when the form_post response_mode is specified' do
+            allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+            authorize! request_param.merge(response_type: 'id_token token', response_mode: 'form_post')
+
+            authorize_response = controller.instance_variable_get :@authorize_response
+            expect(authorize_response.body.to_json).to eq(error_params.to_json)
+            expect(response).to render_template(:form_post)
+          end
+        end
+
+        context 'when not logged in' do
+          let(:error_params) do
+            {
+              'error' => 'login_required',
+              'error_description' => 'The authorization server requires end-user authentication',
+              'state' => 'somestate',
+            }
+          end
+          let(:request_param) { { current_user: nil } }
+
+          it 'returns a login_required error' do
+            authorize! request_param.merge(prompt: 'none', state: 'somestate')
+
+            expect(response).to redirect_to build_redirect_uri(error_params)
+          end
+
+          it 'redirect as the fragment style uri when response_type is implicit flow request' do
+            allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+            authorize! request_param.merge(response_type: 'id_token token', prompt: 'none', state: 'somestate')
+
+            expect(response).to redirect_to build_redirect_uri(error_params, type: 'fragment')
+          end
+
+          it 'set @authorize_response variable and render form_post template and when the form_post response_mode is specified' do
+            allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+            authorize! request_param.merge(response_type: 'id_token token', response_mode: 'form_post', prompt: 'none', state: 'somestate')
+
+            authorize_response = controller.instance_variable_get :@authorize_response
+            expect(authorize_response.body.to_json).to eq(error_params.to_json)
+            expect(response).to render_template(:form_post)
+          end
+        end
+      end
+
+      context 'and no matching token' do
+        it 'redirects to the callback if skip_authorization is set to true' do
+          allow(controller).to receive(:skip_authorization?).and_return(true)
+
+          authorize! prompt: 'none'
+          expect_successful_callback!
+        end
+
+        context 'when not logged in' do
+          let(:error_params) do
+            {
+              'error' => 'login_required',
+              'error_description' => 'The authorization server requires end-user authentication',
+              'state' => 'somestate',
+            }
+          end
+          let(:request_param) { { current_user: nil } }
+
+          it 'returns the login_required error when not logged in' do
+            authorize! request_param.merge(prompt: 'none', state: 'somestate')
+
+            expect(response).to redirect_to build_redirect_uri(error_params)
+          end
+
+          it 'uses the fragment style uris when redirecting an error for implicit flow request' do
+            allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+            authorize! request_param.merge(response_type: 'id_token token', prompt: 'none', state: 'somestate')
+
+            expect(response).to redirect_to build_redirect_uri(error_params, type: 'fragment')
+          end
+
+          it 'set @authorize_response variable and render form_post template and when the form_post response_mode is specified' do
+            allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+            authorize! request_param.merge(response_type: 'id_token token', response_mode: 'form_post', prompt: 'none', state: 'somestate')
+
+            authorize_response = controller.instance_variable_get :@authorize_response
+            expect(authorize_response.body.to_json).to eq(error_params.to_json)
+            expect(response).to render_template(:form_post)
+          end
+        end
+
+        it 'returns a consent_required error when logged in' do
+          authorize! prompt: 'none'
+
+          error_params = {
+            'error' => 'consent_required',
+            'error_description' => 'The authorization server requires end-user consent',
+          }
+
+          expect(response).to redirect_to build_redirect_uri(error_params)
+        end
+      end
+    end
+
+    context 'with a prompt=login parameter' do
+      it 'redirects to the sign in form if not logged in' do
+        authorize! prompt: 'login', current_user: nil
+
+        expect(response).to redirect_to('/login')
+      end
+
+      it 'reauthenticates the user if logged in' do
+        authorize! prompt: 'login'
+
+        expect(response).to redirect_to('/reauthenticate')
+      end
+    end
+
+    context 'with a prompt=consent parameter' do
+      it 'redirects to the sign in form if not logged in' do
+        authorize! prompt: 'consent', current_user: nil
+
+        expect(response).to redirect_to('/login')
+      end
+
+      it 'renders the authorization form even if a matching token is present' do
+        create :access_token, token_attributes
+        authorize! prompt: 'consent'
+
+        expect_authorization_form!
+      end
+    end
+
+    context 'with a prompt=select_account parameter' do
+      it 'redirects to the select account screen' do
+        authorize! prompt: 'select_account'
+
+        expect(response).to redirect_to('/select_account')
+      end
+    end
+
+    context 'with an unknown prompt parameter' do
+      it 'returns an invalid_request error' do
+        authorize! prompt: 'maybe'
+
+        error_params = {
+          'error' => 'invalid_request',
+          'error_description' => 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.',
+        }
+
+        expect(response).to redirect_to build_redirect_uri(error_params)
+      end
+
+      it 'does not redirect to an invalid redirect_uri' do
+        authorize! prompt: 'maybe', redirect_uri: 'https://evilapp.com'
+
+        expect(response).not_to be_redirect
+      end
+    end
+  end
+
+  describe '#handle_oidc_max_age_param!' do
+    context 'with an invalid max_age parameter' do
+      it 'renders the authorization form' do
+        %w[0 -1 -23 foobar].each do |max_age|
+          authorize! max_age: max_age
+
+          expect_authorization_form!
+        end
+      end
+    end
+
+    context 'with a max_age=10 parameter' do
+      it 'renders the authorization form if the users last login was within 10 seconds' do
+        user.update! current_sign_in_at: 5.seconds.ago
+        authorize! max_age: 10
+
+        expect_authorization_form!
+      end
+
+      it 'reauthenticates the user if the last login was longer than 10 seconds ago' do
+        user.update! current_sign_in_at: 5.minutes.ago
+        authorize! max_age: 10
+
+        expect(response).to redirect_to '/reauthenticate'
+      end
+
+      it 'reauthenticates the user if the last login is unknown' do
+        user.update! current_sign_in_at: nil
+        authorize! max_age: 10
+
+        expect(response).to redirect_to '/reauthenticate'
+      end
+    end
+  end
+
+  describe '#reauthenticate_oidc_resource_owner' do
+    let(:performed) { true }
+
+    before do
+      allow(subject).to receive(:performed?) { performed }
+      allow(subject.request).to receive(:path).and_return('/oauth/authorize')
+      allow(subject.request).to receive(:query_parameters) {
+        { client_id: 'foo', prompt: 'login consent select_account' }.with_indifferent_access
+      }
+    end
+
+    def reauthenticate!
+      passed_args = nil
+
+      Doorkeeper::OpenidConnect.configure do
+        reauthenticate_resource_owner do |*args|
+          passed_args = args
+        end
+      end
+
+      subject.send :reauthenticate_oidc_resource_owner, user
+      passed_args
+    end
+
+    it 'calls reauthenticate_resource_owner with the current user and the return path' do
+      resource_owner, return_to = reauthenticate!
+
+      expect(resource_owner).to eq user
+      expect(return_to).to eq '/oauth/authorize?client_id=foo&prompt=consent+select_account'
+    end
+
+    it 'removes login from the prompt parameter and keeps other values' do
+      _, return_to = reauthenticate!
+      return_params = Rack::Utils.parse_query(URI.parse(return_to).query)
+
+      expect(return_params['prompt']).to eq 'consent select_account'
+    end
+
+    context 'with a reauthenticator that does not generate a response' do
+      let(:performed) { false }
+
+      it 'raises a login_required error' do
+        expect do
+          reauthenticate!
+        end.to raise_error(Doorkeeper::OpenidConnect::Errors::LoginRequired)
+      end
+    end
+  end
+
+  describe '#select_account_for_resource_owner' do
+    before do
+      allow(subject.request).to receive(:path).and_return('/oauth/authorize')
+      allow(subject.request).to receive(:query_parameters) {
+        { client_id: 'foo', prompt: 'login consent select_account' }.with_indifferent_access
+      }
+    end
+
+    def select_account!
+      passed_args = nil
+
+      Doorkeeper::OpenidConnect.configure do
+        select_account_for_resource_owner do |*args|
+          passed_args = args
+        end
+      end
+
+      subject.send :select_account_for_oidc_resource_owner, user
+      passed_args
+    end
+
+    it 'calls select_account_for_resource_owner with the current user and the return path' do
+      resource_owner, return_to = select_account!
+
+      expect(resource_owner).to eq user
+      expect(return_to).to eq '/oauth/authorize?client_id=foo&prompt=login+consent'
+    end
+
+    it 'removes select_account from the prompt parameter and keeps other values' do
+      _, return_to = select_account!
+      return_params = Rack::Utils.parse_query(URI.parse(return_to).query)
+
+      expect(return_params['prompt']).to eq 'login consent'
+    end
+  end
+
+  describe '#pre_auth' do
+    it 'permits nonce parameter' do
+      authorize! nonce: '123456'
+      expect(assigns(:pre_auth).nonce).to eq '123456'
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorized_applications_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorized_applications_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f5e43afc519d81ce534dd3316409c8e23caaeffb
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorized_applications_controller_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::AuthorizedApplicationsController, type: :controller do
+  let(:access_token) { create :access_token }
+
+  describe '#index' do
+    it 'does not run the extended #authenticate_resource_owner!' do
+      expect do
+        get :index
+      end.not_to raise_error
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/userinfo_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/userinfo_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ba7007ae5c163c62dc0df5c6b4a3b155e0a732b0
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/userinfo_controller_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::UserinfoController, type: :controller do
+  let(:client) { create :application }
+  let(:user)   { create :user, name: 'Joe' }
+  let(:token)  { create :access_token, application: client, resource_owner_id: user.id }
+
+  describe '#show' do
+    context 'with a valid access token authorized for the openid scope' do
+      let(:token) { create :access_token, application: client, resource_owner_id: user.id, scopes: 'openid' }
+
+      it 'returns the basic user information as JSON' do
+        get :show, params: { access_token: token.token }
+
+        expect(response.status).to eq 200
+        expect(JSON.parse(response.body)).to eq({
+          'sub'                => user.id.to_s,
+          'variable_name'      => 'openid-name',
+          'created_at'         => user.created_at.to_i,
+          'token_id'           => token.id,
+          'both_responses'     => 'both',
+          'user_info_response' => 'user_info',
+        })
+      end
+    end
+
+    context 'with a valid access token authorized for the openid and profile scopes' do
+      let(:token) { create :access_token, application: client, resource_owner_id: user.id, scopes: 'openid profile' }
+
+      it 'returns the full user information as JSON' do
+        get :show, params: { access_token: token.token }
+
+        expect(response.status).to eq 200
+        expect(JSON.parse(response.body)).to eq({
+          'sub'                => user.id.to_s,
+          'name'               => 'Joe',
+          'variable_name'      => 'profile-name',
+          'created_at'         => user.created_at.to_i,
+          'updated_at'         => user.updated_at.to_i,
+          'token_id'           => token.id,
+          'both_responses'     => 'both',
+          'user_info_response' => 'user_info',
+        })
+      end
+    end
+
+    context 'with a valid access token not authorized for the openid scope' do
+      it 'returns an error' do
+        get :show, params: { access_token: token.token }
+
+        expect(response.status).to eq 403
+      end
+    end
+
+    context 'without a valid access token' do
+      it 'returns an error' do
+        get :show, params: { access_token: 'foobar' }
+
+        expect(response.status).to eq 401
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/Rakefile b/vendor/gems/doorkeeper-openid_connect/spec/dummy/Rakefile
new file mode 100644
index 0000000000000000000000000000000000000000..488c551fee2cd158e9f36f0366afd08c9522c2b2
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/Rakefile
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require_relative 'config/application'
+
+Rails.application.load_tasks
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/config/manifest.js b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/config/manifest.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb109908b29eb87e126cdc1a5b3aab84607a509b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/config/manifest.js
@@ -0,0 +1,3 @@
+
+//= link_tree ../images
+//= link_directory ../stylesheets .css
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/images/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/images/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/javascripts/application.js b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/javascripts/application.js
new file mode 100644
index 0000000000000000000000000000000000000000..e54c6461cc303fa0c721e5431b1066b87c7ee56e
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/javascripts/application.js
@@ -0,0 +1,13 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
+// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// compiled file. JavaScript code in this file should be added after the last require_* statement.
+//
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
+// about supported directives.
+//
+//= require_tree .
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/stylesheets/application.css b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/stylesheets/application.css
new file mode 100644
index 0000000000000000000000000000000000000000..0ebd7fe8299ebee6f56fa726f834e4264d27d39d
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/stylesheets/application.css
@@ -0,0 +1,15 @@
+/*
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
+ * listed below.
+ *
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
+ *
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
+ * files in this directory. Styles in this file should be added after the last require_* statement.
+ * It is generally better to create a new file per style scope.
+ *
+ *= require_tree .
+ *= require_self
+ */
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/channel.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/channel.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9aec2305390f808ce1accaed3fccddefb742cb69
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/channel.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module ApplicationCable
+  class Channel < ActionCable::Channel::Base
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/connection.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/connection.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8d6c2a1bf4bbe843bcd32ca6237eecfe73c9012c
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/connection.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module ApplicationCable
+  class Connection < ActionCable::Connection::Base
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/application_controller.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/application_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..280cc28ce21a03e69b50ee7eedb87c6f36a80df7
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/application_controller.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class ApplicationController < ActionController::Base
+  protect_from_forgery with: :exception
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/concerns/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/concerns/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/helpers/application_helper.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/helpers/application_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..15b06f0f67929529e41d73299adb008f8a9e7086
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/helpers/application_helper.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+module ApplicationHelper
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/jobs/application_job.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/jobs/application_job.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d92ffddcb5288f618f89df28148c17052bf143b7
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/jobs/application_job.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+class ApplicationJob < ActiveJob::Base
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/mailers/application_mailer.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/mailers/application_mailer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d84cb6e71e954ad890132d7db2834afd364cd18d
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/mailers/application_mailer.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class ApplicationMailer < ActionMailer::Base
+  default from: 'from@example.com'
+  layout 'mailer'
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/application_record.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/application_record.rb
new file mode 100644
index 0000000000000000000000000000000000000000..71fbba5b32873f53ea6e713ea0219acda01a9286
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/application_record.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class ApplicationRecord < ActiveRecord::Base
+  self.abstract_class = true
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/concerns/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/concerns/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/user.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/user.rb
new file mode 100644
index 0000000000000000000000000000000000000000..53124f5cce8cedd33876510e6c12687fab8de181
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/user.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class User < ActiveRecord::Base
+  def self.authenticate!(name, password)
+    User.where(name: name, password: password).first
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/bundle b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/bundle
new file mode 100755
index 0000000000000000000000000000000000000000..2dbb71769eb0492801d34e71b50794e639041575
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/bundle
@@ -0,0 +1,5 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+load Gem.bin_path('bundler', 'bundle')
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rails b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rails
new file mode 100755
index 0000000000000000000000000000000000000000..a31728ab9778f998cfcbce903d930e94ed287e3b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rails
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+APP_PATH = File.expand_path('../config/application', __dir__)
+require_relative '../config/boot'
+require 'rails/commands'
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rake b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rake
new file mode 100755
index 0000000000000000000000000000000000000000..c199955006061df3143975173ccad6d7fa3cb83a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rake
@@ -0,0 +1,6 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require_relative '../config/boot'
+require 'rake'
+Rake.application.run
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/setup b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/setup
new file mode 100755
index 0000000000000000000000000000000000000000..31400462308caacaba0fa49d1cc33cdf056584c6
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/setup
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('..', __dir__)
+
+def system!(*args)
+  system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+  # This script is a starting point to setup your application.
+  # Add necessary setup steps to this file.
+
+  puts '== Installing dependencies =='
+  system! 'gem install bundler --conservative'
+  system('bundle check') || system!('bundle install')
+
+  # puts "\n== Copying sample files =="
+  # unless File.exist?('config/database.yml')
+  #   cp 'config/database.yml.sample', 'config/database.yml'
+  # end
+
+  puts "\n== Preparing database =="
+  system! 'bin/rails db:setup'
+
+  puts "\n== Removing old logs and tempfiles =="
+  system! 'bin/rails log:clear tmp:clear'
+
+  puts "\n== Restarting application server =="
+  system! 'bin/rails restart'
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/update b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/update
new file mode 100755
index 0000000000000000000000000000000000000000..1d6aa6a5c935e6c91ff19525e86c498b5250849c
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/update
@@ -0,0 +1,31 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('..', __dir__)
+
+def system!(*args)
+  system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+  # This script is a way to update your development environment automatically.
+  # Add necessary update steps to this file.
+
+  puts '== Installing dependencies =='
+  system! 'gem install bundler --conservative'
+  system('bundle check') || system!('bundle install')
+
+  puts "\n== Updating database =="
+  system! 'bin/rails db:migrate'
+
+  puts "\n== Removing old logs and tempfiles =="
+  system! 'bin/rails log:clear tmp:clear'
+
+  puts "\n== Restarting application server =="
+  system! 'bin/rails restart'
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config.ru b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config.ru
new file mode 100644
index 0000000000000000000000000000000000000000..842bccc3402da2e8f1e3e6cf12da39170ca422cc
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config.ru
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+# This file is used by Rack-based servers to start the application.
+
+require_relative 'config/environment'
+
+run Rails.application
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/application.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/application.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f56092cf5d4fc62d93ff8561be0d9ca5480e9751
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/application.rb
@@ -0,0 +1,16 @@
+require_relative 'boot'
+
+# Pick the frameworks you want:
+require "active_record/railtie"
+require "action_controller/railtie"
+require "action_view/railtie"
+
+Bundler.require(*Rails.groups)
+
+module Dummy
+  class Application < Rails::Application
+    # Settings in config/environments/* take precedence over those specified here.
+    # Application configuration should go into files in config/initializers
+    # -- all .rb files in that directory are automatically loaded.
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/boot.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/boot.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c9aef85d4041faa346d7b6375cedaa1163ae2b43
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/boot.rb
@@ -0,0 +1,5 @@
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
+
+require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
+$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/database.yml b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/database.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5403ee52818c4a4484690fdfcc5be1d227edce18
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/database.yml
@@ -0,0 +1,26 @@
+# SQLite version 3.x
+#   gem install sqlite3
+#
+#   Ensure the SQLite 3 gem is defined in your Gemfile
+#   gem 'sqlite3'
+#
+development:
+  adapter: sqlite3
+  pool: 5
+  timeout: 5000
+  database: db/development.sqlite3
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+  adapter: sqlite3
+  pool: 5
+  timeout: 5000
+  database: db/test.sqlite3
+
+production:
+  adapter: sqlite3
+  pool: 5
+  timeout: 5000
+  database: db/production.sqlite3
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environment.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environment.rb
new file mode 100644
index 0000000000000000000000000000000000000000..426333bb46978d897be4cc6fac77b9fcaacf59d0
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require_relative 'application'
+
+# Initialize the Rails application.
+Rails.application.initialize!
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environments/test.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environments/test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1df1a5931abab163ffe0a0552d14a510bb3b5cd0
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environments/test.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+Rails.application.configure do
+  # Settings specified here will take precedence over those in config/application.rb.
+
+  # The test environment is used exclusively to run your application's
+  # test suite. You never need to work with it otherwise. Remember that
+  # your test database is "scratch space" for the test suite and is wiped
+  # and recreated between test runs. Don't rely on the data there!
+  config.cache_classes = true
+
+  # Do not eager load code on boot. This avoids loading your whole application
+  # just for the purpose of running a single test. If you are using a tool that
+  # preloads Rails for running tests, you may have to set it to true.
+  config.eager_load = false
+
+  # Show full error reports and disable caching.
+  config.consider_all_requests_local       = true
+  config.action_controller.perform_caching = false
+
+  # Raise exceptions instead of rendering exception templates.
+  config.action_dispatch.show_exceptions = false
+
+  # Disable request forgery protection in test environment.
+  config.action_controller.allow_forgery_protection = false
+
+  # Print deprecation notices to the stderr.
+  config.active_support.deprecation = :stderr
+
+  # Raises error for missing translations
+  # config.action_view.raise_on_missing_translations = true
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a41b1222231a23d9b254088d33bbf6fb673bbca2
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+Doorkeeper.configure do
+  optional_scopes :openid
+
+  resource_owner_authenticator do
+    if params[:current_user].present?
+      User.find(params[:current_user])
+    else
+      redirect_to('/login')
+      nil
+    end
+  end
+
+  grant_flows %w[authorization_code client_credentials implicit_oidc]
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper_openid_connect.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper_openid_connect.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a38197294791824c9fd1292fa3c3ce570ba6e19a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper_openid_connect.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+Doorkeeper::OpenidConnect.configure do
+  issuer 'dummy'
+
+  signing_key <<~EOL
+    -----BEGIN RSA PRIVATE KEY-----
+    MIIEpgIBAAKCAQEAsjdnSA6UWUQQHf6BLIkIEUhMRNBJC1NN/pFt1EJmEiI88GS0
+    ceROO5B5Ooo9Y3QOWJ/n+u1uwTHBz0HCTN4wgArWd1TcqB5GQzQRP4eYnWyPfi4C
+    feqAHzQp+v4VwbcK0LW4FqtW5D0dtrFtI281FDxLhARzkhU2y7fuYhL8fVw5rUhE
+    8uwvHRZ5CEZyxf7BSHxIvOZAAymhuzNLATt2DGkDInU1BmF75tEtBJAVLzWG/j4L
+    PZh1EpSdfezqaXQlcy9PJi916UzTl0P7Yy+ulOdUsMlB6yo8qKTY1+AbZ5jzneHb
+    GDU/O8QjYvii1WDmJ60t0jXicmOkGrOhruOptwIDAQABAoIBAQChYNwMeu9IugJi
+    NsEf4+JDTBWMRpOuRrwcpfIvQAUPrKNEB90COPvCoju0j9OxCDmpdPtq1K/zD6xx
+    khlw485FVAsKufSp4+g6GJ75yT6gZtq1JtKo1L06BFFzb7uh069eeP7+wB6JxPHw
+    KlAqwxvsfADhxeolQUKCTMb3Vjv/Aw2cO/nn6RAOeftw2aDmFy8Xl+oTUtSxyib0
+    YCdU9cK8MxsxDdmowwHp04xRTm/wfG5hLEn7HMz1PP86iP9BiFsCqTId9dxEUTS1
+    K+VAt9FbxRAq5JlBocxUMHNxLigb94Ca2FOMR7F6l/tronLfHD801YoObF0fN9qW
+    Cgw4aTO5AoGBAOR79hiZVM7/l1cBid7hKSeMWKUZ/nrwJsVfNpu1H9xt9uDu+79U
+    mcGfM7pm7L2qCNGg7eeWBHq2CVg/XQacRNtcTlomFrw4tDXUkFN1hE56t1iaTs9m
+    dN9IDr6jFgf6UaoOxxoPT9Q1ZtO46l043Nzrkoz8cBEBaBY20bUDwCYjAoGBAMet
+    tt1ImGF1cx153KbOfjl8v54VYUVkmRNZTa1E821nL/EMpoONSqJmRVsX7grLyPL1
+    QyZe245NOvn63YM0ng0rn2osoKsMVJwYBEYjHL61iF6dPtW5p8FIs7auRnC3NrG0
+    XxHATZ4xhHD0iIn14iXh0XIhUVk+nGktHU1gbmVdAoGBANniwKdqqS6RHKBTDkgm
+    Dhnxw6MGa+CO3VpA1xGboxuRHeoY3KfzpIC5MhojBsZDvQ8zWUwMio7+w2CNZEfm
+    g99wYiOjyPCLXocrAssj+Rzh97AdzuQHf5Jh4/W2Dk9jTbdPSl02ltj2Z+2lnJFz
+    pWNjnqimHrSI09rDQi5NulJjAoGBAImquujVpDmNQFCSNA7NTzlTSMk09FtjgCZW
+    67cKUsqa2fLXRfZs84gD+s1TMks/NMxNTH6n57e0h3TSAOb04AM0kDQjkKJdXfhA
+    lrHEg4z4m4yf3TJ9Tat09HJ+tRIBPzRFp0YVz23Btg4qifiUDdcQWdbWIb/l6vCY
+    qhsu4O4BAoGBANbceYSDYRdT7a5QjJGibkC90Z3vFe4rDTBgZWg7xG0cpSU4JNg7
+    SFR3PjWQyCg7aGGXiooCM38YQruACTj0IFub24MFRA4ZTXvrACvpsVokJlQiG0Z4
+    tuQKYki41JvYqPobcq/rLE/AM7PKJftW35nqFuj0MrsUwPacaVwKBf5J
+    -----END RSA PRIVATE KEY-----
+  EOL
+
+  subject_types_supported [:public]
+
+  resource_owner_from_access_token do |access_token|
+    User.find_by(id: access_token.resource_owner_id)
+  end
+
+  auth_time_from_resource_owner do |resource_owner|
+    resource_owner.current_sign_in_at
+  end
+
+  reauthenticate_resource_owner do |_resource_owner, _return_to|
+    redirect_to '/reauthenticate'
+  end
+
+  select_account_for_resource_owner do |_resource_owner, _return_to|
+    redirect_to '/select_account'
+  end
+
+  subject do |resource_owner|
+    resource_owner.id
+  end
+
+  claims do
+    claim :name do |user|
+      user.name
+    end
+
+    claim :variable_name, scope: :openid do |user, scopes|
+      scopes.exists?(:profile) ? 'profile-name' : 'openid-name'
+    end
+
+    claim :created_at, scope: :openid do |user|
+      user.created_at.to_i
+    end
+
+    claim :updated_at do |user|
+      user.updated_at.to_i
+    end
+
+    claim :token_id, scope: :openid do |user, scopes, token|
+      token.id
+    end
+
+    claim(:both_responses, scope: :openid, response: [:id_token, :user_info]) { 'both' }
+    claim(:id_token_response, scope: :openid, response: [:id_token]) { 'id_token' }
+    claim(:user_info_response, scope: :openid, response: :user_info) { 'user_info' }
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/locales/doorkeeper_openid_connect.en.yml b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/locales/doorkeeper_openid_connect.en.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1bed506b2cf19142aac85a474e901e8bab8f5253
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/locales/doorkeeper_openid_connect.en.yml
@@ -0,0 +1,23 @@
+en:
+  doorkeeper:
+    scopes:
+      openid: 'Authenticate your account'
+      profile: 'View your profile information'
+      email: 'View your email address'
+      address: 'View your physical address'
+      phone: 'View your phone number'
+    errors:
+      messages:
+        login_required: 'The authorization server requires end-user authentication'
+        consent_required: 'The authorization server requires end-user consent'
+        interaction_required: 'The authorization server requires end-user interaction'
+        account_selection_required: 'The authorization server requires end-user account selection'
+    openid_connect:
+      errors:
+        messages:
+          # Configuration error messages
+          resource_owner_from_access_token_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.resource_owner_from_access_token missing configuration.'
+          auth_time_from_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.auth_time_from_resource_owner missing configuration.'
+          reauthenticate_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.reauthenticate_resource_owner missing configuration.'
+          select_account_for_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.select_account_for_resource_owner missing configuration.'
+          subject_not_configured: 'ID Token generation failed due to Doorkeeper::OpenidConnect.configure.subject missing configuration.'
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/routes.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/routes.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e182346eb5312c1b395fdd8d3344bcd60d4afc8a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/routes.rb
@@ -0,0 +1,6 @@
+Rails.application.routes.draw do
+  use_doorkeeper
+  use_doorkeeper_openid_connect
+
+  root 'dummy#index'
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/secrets.yml b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/secrets.yml
new file mode 100644
index 0000000000000000000000000000000000000000..77b0f4db7a46773e80a1399f1c4b77efebebaa51
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/secrets.yml
@@ -0,0 +1,22 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key is used for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+# You can use `rails secret` to generate a secure secret key.
+
+# Make sure the secrets in this file are kept private
+# if you're sharing your code publicly.
+
+development:
+  secret_key_base: 047f8d91118b6fad743ccac15928b306d1880d9d104377eb1f7aeed909ce852c0a214074742163a6e0bc814482c8cdeae470c5edfc75eee37c8da6ccbbae4199
+
+test:
+  secret_key_base: 88becc3eb1c84af38da6deea4627f29f2bd41ba79dd279a0e379a41a82f18316f6f5221c73182adca329df8be13fd7c115804a82246989f1314e93d7efc745d3
+
+# Do not keep production secrets in the repository,
+# instead read values from the environment.
+production:
+  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20111122132257_create_users.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20111122132257_create_users.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3991429575b71e4731461e7d9c89d1ef068a0bab
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20111122132257_create_users.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class CreateUsers < ActiveRecord::Migration[4.2]
+  def change
+    create_table :users do |t|
+      t.string :name
+
+      t.timestamps
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb
new file mode 100644
index 0000000000000000000000000000000000000000..67d3728c6c49f5d1fa9d61b19062c8918be89e20
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddPasswordToUsers < ActiveRecord::Migration[4.2]
+  def change
+    add_column :users, :password, :string
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb
new file mode 100644
index 0000000000000000000000000000000000000000..91bdbf507464bd2662d14df2865ad9a0c57dacdf
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+class CreateDoorkeeperTables < ActiveRecord::Migration[4.2]
+  def change
+    create_table :oauth_applications do |t|
+      t.string  :name,         null: false
+      t.string  :uid,          null: false
+      t.string  :secret,       null: false
+      t.text    :redirect_uri, null: false
+      t.string  :scopes,       null: false, default: ''
+      t.timestamps             null: false
+    end
+
+    add_index :oauth_applications, :uid, unique: true
+
+    create_table :oauth_access_grants do |t|
+      t.integer  :resource_owner_id, null: false
+      t.references :application,     null: false
+      t.string   :token,             null: false
+      t.integer  :expires_in,        null: false
+      t.text     :redirect_uri,      null: false
+      t.datetime :created_at,        null: false
+      t.datetime :revoked_at
+      t.string   :scopes
+    end
+
+    add_index :oauth_access_grants, :token, unique: true
+    add_foreign_key(
+      :oauth_access_grants,
+      :oauth_applications,
+      column: :application_id,
+    )
+
+    create_table :oauth_access_tokens do |t|
+      t.integer  :resource_owner_id
+      t.references :application
+
+      # If you use a custom token generator you may need to change this column
+      # from string to text, so that it accepts tokens larger than 255
+      # characters. More info on custom token generators in:
+      # https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator
+      #
+      # t.text     :token,             null: false
+      t.string   :token,             null: false
+
+      t.string   :refresh_token
+      t.integer  :expires_in
+      t.datetime :revoked_at
+      t.datetime :created_at,        null: false
+      t.string   :scopes
+    end
+
+    add_index :oauth_access_tokens, :token, unique: true
+    add_index :oauth_access_tokens, :resource_owner_id
+    add_index :oauth_access_tokens, :refresh_token, unique: true
+    add_foreign_key(
+      :oauth_access_tokens,
+      :oauth_applications,
+      column: :application_id,
+    )
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d4eda38df0f1c138729fedb44084ccd19d30198e
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddOwnerToApplication < ActiveRecord::Migration[4.2]
+  def change
+    add_column :oauth_applications, :owner_id, :integer, null: true
+    add_column :oauth_applications, :owner_type, :string, null: true
+    add_index :oauth_applications, [:owner_id, :owner_type]
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ffad61b260a8a96a6d01779e601d3838d57bd40a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddPreviousRefreshTokenToAccessTokens < ActiveRecord::Migration[4.2]
+  def change
+    add_column(
+      :oauth_access_tokens,
+      :previous_refresh_token,
+      :string,
+      default: '',
+      null: false
+    )
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20161102204540_add_current_sign_in_at_to_users.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20161102204540_add_current_sign_in_at_to_users.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6b5d2ba96f1e1c94eaf80d396c8d459c956fe539
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20161102204540_add_current_sign_in_at_to_users.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddCurrentSignInAtToUsers < ActiveRecord::Migration[4.2]
+  def change
+    add_column :users, :current_sign_in_at, :datetime
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20180904152859_add_confidential_to_applications.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20180904152859_add_confidential_to_applications.rb
new file mode 100644
index 0000000000000000000000000000000000000000..784af8828f5c3d4d0d787fbc8489b9e4c9595424
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20180904152859_add_confidential_to_applications.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddConfidentialToApplications < ActiveRecord::Migration[5.0]
+  def change
+    add_column(
+      :oauth_applications,
+      :confidential,
+      :boolean,
+      null: false,
+      default: true
+    )
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20221122044143_enable_pkce.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20221122044143_enable_pkce.rb
new file mode 100644
index 0000000000000000000000000000000000000000..96b4e1f7a3f24c800633e15b90ec7452975430d0
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20221122044143_enable_pkce.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class EnablePkce < ActiveRecord::Migration[6.0]
+  def change
+    add_column :oauth_access_grants, :code_challenge, :string, null: true
+    add_column :oauth_access_grants, :code_challenge_method, :string, null: true
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/schema.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/schema.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8c4e100b4804a93bff5279b21f0eee9db4c703de
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/schema.rb
@@ -0,0 +1,76 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `rails
+# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema.define(version: 2022_11_22_044143) do
+
+  create_table "oauth_access_grants", force: :cascade do |t|
+    t.integer "resource_owner_id", null: false
+    t.integer "application_id", null: false
+    t.string "token", null: false
+    t.integer "expires_in", null: false
+    t.text "redirect_uri", null: false
+    t.datetime "created_at", null: false
+    t.datetime "revoked_at"
+    t.string "scopes"
+    t.string "code_challenge"
+    t.string "code_challenge_method"
+    t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true
+  end
+
+  create_table "oauth_access_tokens", force: :cascade do |t|
+    t.integer "resource_owner_id"
+    t.integer "application_id"
+    t.string "token", null: false
+    t.string "refresh_token"
+    t.integer "expires_in"
+    t.datetime "revoked_at"
+    t.datetime "created_at", null: false
+    t.string "scopes"
+    t.string "previous_refresh_token", default: "", null: false
+    t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true
+    t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id"
+    t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true
+  end
+
+  create_table "oauth_applications", force: :cascade do |t|
+    t.string "name", null: false
+    t.string "uid", null: false
+    t.string "secret", null: false
+    t.text "redirect_uri", null: false
+    t.string "scopes", default: "", null: false
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.integer "owner_id"
+    t.string "owner_type"
+    t.boolean "confidential", default: true, null: false
+    t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type"
+    t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true
+  end
+
+  create_table "oauth_openid_requests", force: :cascade do |t|
+    t.integer "access_grant_id", null: false
+    t.string "nonce", null: false
+    t.index ["access_grant_id"], name: "index_oauth_openid_requests_on_access_grant_id"
+  end
+
+  create_table "users", force: :cascade do |t|
+    t.string "name"
+    t.datetime "created_at"
+    t.datetime "updated_at"
+    t.string "password"
+    t.datetime "current_sign_in_at"
+  end
+
+  add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id"
+  add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id"
+  add_foreign_key "oauth_openid_requests", "oauth_access_grants", column: "access_grant_id", on_delete: :cascade
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/lib/assets/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/lib/assets/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/log/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/log/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/404.html b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/404.html
new file mode 100644
index 0000000000000000000000000000000000000000..b612547fc21d079889046e65d1fb135ec6921eaa
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/404.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>The page you were looking for doesn't exist (404)</title>
+  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <style>
+  body {
+    background-color: #EFEFEF;
+    color: #2E2F30;
+    text-align: center;
+    font-family: arial, sans-serif;
+    margin: 0;
+  }
+
+  div.dialog {
+    width: 95%;
+    max-width: 33em;
+    margin: 4em auto 0;
+  }
+
+  div.dialog > div {
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #BBB;
+    border-top: #B00100 solid 4px;
+    border-top-left-radius: 9px;
+    border-top-right-radius: 9px;
+    background-color: white;
+    padding: 7px 12% 0;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+
+  h1 {
+    font-size: 100%;
+    color: #730E15;
+    line-height: 1.5em;
+  }
+
+  div.dialog > p {
+    margin: 0 0 1em;
+    padding: 1em;
+    background-color: #F7F7F7;
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #999;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+    border-top-color: #DADADA;
+    color: #666;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+  </style>
+</head>
+
+<body>
+  <!-- This file lives in public/404.html -->
+  <div class="dialog">
+    <div>
+      <h1>The page you were looking for doesn't exist.</h1>
+      <p>You may have mistyped the address or the page may have moved.</p>
+    </div>
+    <p>If you are the application owner check the logs for more information.</p>
+  </div>
+</body>
+</html>
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/422.html b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/422.html
new file mode 100644
index 0000000000000000000000000000000000000000..a21f82b3bdb817ecbc43f74c6fe360300739418a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/422.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>The change you wanted was rejected (422)</title>
+  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <style>
+  body {
+    background-color: #EFEFEF;
+    color: #2E2F30;
+    text-align: center;
+    font-family: arial, sans-serif;
+    margin: 0;
+  }
+
+  div.dialog {
+    width: 95%;
+    max-width: 33em;
+    margin: 4em auto 0;
+  }
+
+  div.dialog > div {
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #BBB;
+    border-top: #B00100 solid 4px;
+    border-top-left-radius: 9px;
+    border-top-right-radius: 9px;
+    background-color: white;
+    padding: 7px 12% 0;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+
+  h1 {
+    font-size: 100%;
+    color: #730E15;
+    line-height: 1.5em;
+  }
+
+  div.dialog > p {
+    margin: 0 0 1em;
+    padding: 1em;
+    background-color: #F7F7F7;
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #999;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+    border-top-color: #DADADA;
+    color: #666;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+  </style>
+</head>
+
+<body>
+  <!-- This file lives in public/422.html -->
+  <div class="dialog">
+    <div>
+      <h1>The change you wanted was rejected.</h1>
+      <p>Maybe you tried to change something you didn't have access to.</p>
+    </div>
+    <p>If you are the application owner check the logs for more information.</p>
+  </div>
+</body>
+</html>
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/500.html b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/500.html
new file mode 100644
index 0000000000000000000000000000000000000000..061abc587dcac4cdb1d62a890e4fd4bb20b8cb61
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/500.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>We're sorry, but something went wrong (500)</title>
+  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <style>
+  body {
+    background-color: #EFEFEF;
+    color: #2E2F30;
+    text-align: center;
+    font-family: arial, sans-serif;
+    margin: 0;
+  }
+
+  div.dialog {
+    width: 95%;
+    max-width: 33em;
+    margin: 4em auto 0;
+  }
+
+  div.dialog > div {
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #BBB;
+    border-top: #B00100 solid 4px;
+    border-top-left-radius: 9px;
+    border-top-right-radius: 9px;
+    background-color: white;
+    padding: 7px 12% 0;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+
+  h1 {
+    font-size: 100%;
+    color: #730E15;
+    line-height: 1.5em;
+  }
+
+  div.dialog > p {
+    margin: 0 0 1em;
+    padding: 1em;
+    background-color: #F7F7F7;
+    border: 1px solid #CCC;
+    border-right-color: #999;
+    border-left-color: #999;
+    border-bottom-color: #999;
+    border-bottom-left-radius: 4px;
+    border-bottom-right-radius: 4px;
+    border-top-color: #DADADA;
+    color: #666;
+    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
+  }
+  </style>
+</head>
+
+<body>
+  <!-- This file lives in public/500.html -->
+  <div class="dialog">
+    <div>
+      <h1>We're sorry, but something went wrong.</h1>
+    </div>
+    <p>If you are the application owner check the logs for more information.</p>
+  </div>
+</body>
+</html>
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/favicon.ico b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/factories.rb b/vendor/gems/doorkeeper-openid_connect/spec/factories.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2b30682e1de8e1eaece636380ddb50f356c1ea37
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/factories.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+  factory :access_grant, class: 'Doorkeeper::AccessGrant' do
+    resource_owner_id { create(:user).id }
+    application
+    redirect_uri { 'https://app.com/callback' }
+    expires_in { 100 }
+    scopes { 'public write' }
+  end
+
+  factory :access_token, class: 'Doorkeeper::AccessToken' do
+    resource_owner_id { create(:user).id }
+    application
+    expires_in { 2.hours }
+
+    factory :clientless_access_token do
+      application { nil }
+    end
+  end
+
+  factory :application, class: 'Doorkeeper::Application' do
+    sequence(:name) { |n| "Application #{n}" }
+    redirect_uri { 'https://app.com/callback' }
+  end
+
+  factory :user do
+    current_sign_in_at { Time.zone.at(23) }
+  end
+
+  factory :openid_request, class: 'Doorkeeper::OpenidConnect::Request' do
+    access_grant
+    sequence(:nonce, &:to_s)
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/claims/claim_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/claims/claim_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..24e66e8228f3c2c8a8044d8de12eaf212db7069b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/claims/claim_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::Claims::Claim do
+  subject { described_class.new name: 'username', scope: 'profile' }
+
+  describe '#initialize' do
+    it 'uses the given name' do
+      expect(subject.name).to eq :username
+    end
+
+    it 'uses the given scope' do
+      expect(subject.scope).to eq :profile
+    end
+
+    it 'falls back to the default scope for standard claims' do
+      expect(described_class.new(name: 'family_name').scope).to eq :profile
+      expect(described_class.new(name: :family_name).scope).to eq :profile
+      expect(described_class.new(name: 'email').scope).to eq :email
+      expect(described_class.new(name: :email).scope).to eq :email
+      expect(described_class.new(name: 'address').scope).to eq :address
+      expect(described_class.new(name: :address).scope).to eq :address
+      expect(described_class.new(name: 'phone_number').scope).to eq :phone
+      expect(described_class.new(name: :phone_number).scope).to eq :phone
+    end
+
+    it 'falls back to the profile scope for non-standard claims' do
+      expect(described_class.new(name: 'unknown').scope).to eq :profile
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/config_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/config_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5de7af5d14a6438266491fc9c7faa88ca9779d01
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/config_spec.rb
@@ -0,0 +1,232 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect, 'configuration' do
+  subject { described_class.configuration }
+
+  describe '#configure' do
+    it 'fails if not set to :active_record' do
+      # stub ORM setup to avoid Doorkeeper exceptions
+      allow(Doorkeeper).to receive(:setup_orm_adapter)
+      allow(Doorkeeper).to receive(:setup_orm_models)
+      allow(Doorkeeper).to receive(:setup_application_owner)
+
+      Doorkeeper.configure do
+        orm :mongoid
+      end
+
+      expect do
+        described_class.configure {}
+      end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration
+    end
+  end
+
+  describe 'jws_private_key' do
+    it 'delegates to signing_key' do
+      value = 'private_key'
+      described_class.configure do
+        jws_private_key value
+      end
+      expect(subject.signing_key).to eq(value)
+    end
+  end
+
+  describe 'signing_key' do
+    it 'sets the value that is accessible via signing_key' do
+      value = 'private_key'
+      described_class.configure do
+        signing_key value
+      end
+      expect(subject.signing_key).to eq(value)
+    end
+  end
+
+  describe 'issuer' do
+    it 'sets the value that is accessible via issuer' do
+      value = 'issuer'
+      described_class.configure do
+        issuer value
+      end
+      expect(subject.issuer).to eq(value)
+    end
+
+    it 'sets the block that is accessible via issuer' do
+      block = proc {}
+      described_class.configure do
+        issuer(&block)
+      end
+      expect(subject.issuer).to eq(block)
+    end
+  end
+
+  describe 'resource_owner_from_access_token' do
+    it 'sets the block that is accessible via resource_owner_from_access_token' do
+      block = proc {}
+      described_class.configure do
+        resource_owner_from_access_token(&block)
+      end
+      expect(subject.resource_owner_from_access_token).to eq(block)
+    end
+
+    it 'fails if unset' do
+      described_class.configure {}
+
+      expect do
+        subject.resource_owner_from_access_token.call
+      end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration
+    end
+  end
+
+  describe 'auth_time_from_resource_owner' do
+    it 'sets the block that is accessible via auth_time_from_resource_owner' do
+      block = proc {}
+      described_class.configure do
+        auth_time_from_resource_owner(&block)
+      end
+      expect(subject.auth_time_from_resource_owner).to eq(block)
+    end
+
+    it 'fails if unset' do
+      described_class.configure {}
+
+      expect do
+        subject.auth_time_from_resource_owner.call
+      end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration
+    end
+  end
+
+  describe 'reauthenticate_resource_owner' do
+    it 'sets the block that is accessible via reauthenticate_resource_owner' do
+      block = proc {}
+      described_class.configure do
+        reauthenticate_resource_owner(&block)
+      end
+      expect(subject.reauthenticate_resource_owner).to eq(block)
+    end
+
+    it 'fails if unset' do
+      described_class.configure {}
+
+      expect do
+        subject.reauthenticate_resource_owner.call
+      end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration
+    end
+  end
+
+  describe 'select_account_for_resource_owner' do
+    it 'sets the block that is accessible via select_account_for_resource_owner' do
+      block = proc {}
+      described_class.configure do
+        select_account_for_resource_owner(&block)
+      end
+      expect(subject.select_account_for_resource_owner).to eq(block)
+    end
+
+    it 'fails if unset' do
+      described_class.configure {}
+
+      expect do
+        subject.select_account_for_resource_owner.call
+      end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration
+    end
+  end
+
+  describe 'subject' do
+    it 'sets the block that is accessible via subject' do
+      block = proc {}
+      described_class.configure do
+        subject(&block)
+      end
+      expect(subject.subject).to eq(block)
+    end
+
+    it 'fails if unset' do
+      described_class.configure {}
+
+      expect do
+        subject.subject.call
+      end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration
+    end
+  end
+
+  describe 'expiration' do
+    it 'sets the value that is accessible via expiration' do
+      value = 'expiration'
+      described_class.configure do
+        expiration value
+      end
+      expect(subject.expiration).to eq(value)
+    end
+  end
+
+  describe 'claims' do
+    it 'sets the claims configuration that is accessible via claims' do
+      described_class.configure do
+        claims do
+        end
+      end
+      expect(subject.claims).not_to be_nil
+    end
+  end
+
+  describe 'protocol' do
+    it 'defaults to https in production' do
+      expect(::Rails.env).to receive(:production?).and_return(true)
+
+      expect(subject.protocol.call).to eq(:https)
+    end
+
+    it 'defaults to http in other environments' do
+      expect(::Rails.env).to receive(:production?).and_return(false)
+
+      expect(subject.protocol.call).to eq(:http)
+    end
+
+    it 'can be set to other protocols' do
+      described_class.configure do
+        protocol { :ftp }
+      end
+
+      expect(subject.protocol.call).to eq(:ftp)
+    end
+  end
+
+  describe 'end_session_endpoint' do
+    it 'defaults to nil' do
+      expect(subject.end_session_endpoint.call).to be_nil
+    end
+
+    it 'can be set to a custom url' do
+      described_class.configure do
+        end_session_endpoint { 'http://test.host/logout' }
+      end
+
+      expect(subject.end_session_endpoint.call).to eq('http://test.host/logout')
+    end
+  end
+
+  describe 'discovery_url_options' do
+    it 'defaults to empty hash' do
+      expect(subject.discovery_url_options.call).to be_kind_of(Hash)
+      expect(subject.discovery_url_options.call).to be_empty
+    end
+
+    it 'can be set to other hosts' do
+      Doorkeeper::OpenidConnect.configure do
+        discovery_url_options do |request|
+          {
+            authorization: { host: 'alternate-authorization-host' },
+            token: { host: 'alternate-token-host' },
+            revocation: { host: 'alternate-revocation-host' },
+            introspection: { host: 'alternate-introspection-host' },
+            userinfo: { host: 'alternate-userinfo-host' },
+            jwks: { host: 'alternate-jwks-host' }
+          }
+        end
+      end
+
+      expect(subject.discovery_url_options.call[:authorization]).to eq(host: 'alternate-authorization-host')
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2e9e6722670f4cf22e496e2292f635e7589ef033
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_spec.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::IdToken do
+  subject { described_class.new(access_token, nonce) }
+
+  let(:access_token) { create :access_token, resource_owner_id: user.id, scopes: 'openid' }
+  let(:user) { create :user }
+  let(:nonce) { '123456' }
+
+  before do
+    allow(Time).to receive(:now) { Time.zone.at 60 }
+  end
+
+  describe '#nonce' do
+    it 'returns the stored nonce' do
+      expect(subject.nonce).to eq '123456'
+    end
+  end
+
+  describe '#claims' do
+    it 'returns all default claims' do
+      expect(subject.claims).to eq(
+        iss: 'dummy',
+        sub: user.id.to_s,
+        aud: access_token.application.uid,
+        exp: 180,
+        iat: 60,
+        nonce: nonce,
+        auth_time: 23,
+        both_responses: 'both',
+        id_token_response: 'id_token',
+      )
+    end
+
+    context 'when application is not set on the access token' do
+      before do
+        access_token.application = nil
+      end
+
+      it 'returns all default claims except audience' do
+        expect(subject.claims).to eq(
+          iss: 'dummy',
+          sub: user.id.to_s,
+          aud: nil,
+          exp: 180,
+          iat: 60,
+          nonce: nonce,
+          auth_time: 23,
+          both_responses: 'both',
+          id_token_response: 'id_token',
+        )
+      end
+    end
+  end
+
+  describe '#as_json' do
+    it 'returns claims with nil values and empty strings removed' do
+      allow(subject).to receive(:issuer).and_return(nil)
+      allow(subject).to receive(:subject).and_return('')
+      allow(subject).to receive(:audience).and_return(' ')
+
+      json = subject.as_json
+
+      expect(json).not_to include :iss
+      expect(json).not_to include :sub
+      expect(json).to include :aud
+    end
+  end
+
+  describe '#as_jws_token' do
+    shared_examples 'a jws token' do
+      it 'returns claims encoded as JWT' do
+        algorithms = [Doorkeeper::OpenidConnect.signing_algorithm.to_s]
+
+        data, headers = ::JWT.decode subject.as_jws_token, Doorkeeper::OpenidConnect.signing_key.keypair, true, { algorithms: algorithms }
+
+        expect(data.to_hash).to eq subject.as_json.stringify_keys
+        expect(headers["kid"]).to eq Doorkeeper::OpenidConnect.signing_key.kid
+        expect(headers["alg"]).to eq Doorkeeper::OpenidConnect.signing_algorithm.to_s
+      end
+    end
+
+    it_behaves_like 'a jws token'
+
+    context 'when signing_algorithm is EC' do
+      before { configure_ec }
+
+      it_behaves_like 'a jws token'
+    end
+
+    context 'when signing_algorithm is HMAC' do
+      before { configure_hmac }
+
+      it_behaves_like 'a jws token'
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_token_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_token_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..597fff64008def43cb0c406156af1f00b4f99912
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_token_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::IdTokenToken do
+  subject { described_class.new(access_token, nonce) }
+
+  let(:access_token) { create :access_token, resource_owner_id: user.id, scopes: 'openid' }
+  let(:user) { create :user }
+  let(:nonce) { '123456' }
+
+  before do
+    allow(Time).to receive(:now) { Time.zone.at 60 }
+  end
+
+  describe '#claims' do
+    it 'returns all default claims' do
+      # access token is from http://openid.net/specs/openid-connect-core-1_0.html
+      # so we can test `at_hash` value
+      access_token.update(token: 'jHkWEdUXMU1BwAsC4vtUsZwnNvTIxEl0z9K3vx5KF0Y')
+
+      expect(subject.claims).to eq({
+        iss: 'dummy',
+        sub: user.id.to_s,
+        aud: access_token.application.uid,
+        exp: 180,
+        iat: 60,
+        nonce: nonce,
+        auth_time: 23,
+        at_hash: '77QmUPtjPfzWtF2AnpK9RQ',
+        both_responses: 'both',
+        id_token_response: 'id_token',
+      })
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization/code_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization/code_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0062c109c67795cb102c6f9071570adcc68cd24f
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization/code_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::OAuth::Authorization::Code do
+  subject { Doorkeeper::OAuth::Authorization::Code.new pre_auth, resource_owner }
+
+  let(:resource_owner) { create :user }
+  let(:access_grant) { create :access_grant }
+  let(:pre_auth) { double }
+  let(:client) { double }
+
+  describe '#issue_token' do
+    before do
+      allow(pre_auth).to receive(:client) { client }
+      allow(pre_auth).to receive(:redirect_uri).and_return('redirect_uri')
+      allow(pre_auth).to receive(:scopes).and_return('scopes')
+      allow(pre_auth).to receive(:nonce).and_return('123456')
+      allow(pre_auth).to receive(:code_challenge).and_return('987654')
+      allow(pre_auth).to receive(:code_challenge_method).and_return('plain')
+      allow(pre_auth).to receive(:custom_access_token_attributes).and_return({})
+      allow(client).to receive(:id).and_return('client_id')
+
+      allow(Doorkeeper::AccessGrant).to receive(:create!) { access_grant }
+      allow(Doorkeeper::OpenidConnect::Request).to receive(:create!)
+    end
+
+    it 'stores the nonce' do
+      subject.issue_token
+
+      expect(Doorkeeper::OpenidConnect::Request).to have_received(:create!).with({
+        access_grant: access_grant,
+        nonce: '123456'
+      })
+    end
+
+    it 'does not store the nonce if not present' do
+      allow(pre_auth).to receive(:nonce).and_return(nil)
+      subject.issue_token
+
+      expect(Doorkeeper::OpenidConnect::Request).not_to have_received(:create!)
+    end
+
+    it 'does not store the nonce if blank' do
+      allow(pre_auth).to receive(:nonce).and_return(' ')
+      subject.issue_token
+
+      expect(Doorkeeper::OpenidConnect::Request).not_to have_received(:create!)
+    end
+
+    it 'returns the created grant' do
+      expect(subject.issue_token).to be_a Doorkeeper::AccessGrant
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization_code_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization_code_request_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8e5b242391faef63daef214e445bce521adfd616
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization_code_request_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::OAuth::AuthorizationCodeRequest do
+  subject do
+    Doorkeeper::OAuth::AuthorizationCodeRequest.new(server, grant, client).tap do |request|
+      request.instance_variable_set '@response', response
+      request.instance_variable_set('@access_token', token)
+    end
+  end
+
+  let(:server) { double }
+  let(:client) { double }
+  let(:grant) { create :access_grant, openid_request: openid_request }
+  let(:openid_request) { create :openid_request, nonce: '123456' }
+  let(:token) { create :access_token }
+  let(:response) { Doorkeeper::OAuth::TokenResponse.new token }
+
+  describe '#after_successful_response' do
+    it 'adds the ID token to the response' do
+      subject.send :after_successful_response
+
+      expect(response.id_token).to be_a Doorkeeper::OpenidConnect::IdToken
+      expect(response.id_token.nonce).to eq '123456'
+    end
+
+    it 'destroys the OpenID request record' do
+      grant.save!
+
+      expect do
+        subject.send :after_successful_response
+      end.to change { Doorkeeper::OpenidConnect::Request.count }.by(-1)
+    end
+
+    it 'skips the nonce if not present' do
+      grant.openid_request.nonce = nil
+      subject.send :after_successful_response
+
+      expect(response.id_token.nonce).to be_nil
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_request_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3dd93cc42d2ed009df1309b10fe2edcf70c92663
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_request_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OAuth::IdTokenRequest do
+  subject do
+    described_class.new(pre_auth, owner)
+  end
+
+  let :application do
+    FactoryBot.create(:application, scopes: 'public')
+  end
+
+  let :pre_auth do
+    server = Doorkeeper.configuration
+    allow(server).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+    client = Doorkeeper::OAuth::Client.new(application)
+
+    attributes = {
+      client_id: client.uid,
+      response_type: 'id_token',
+      redirect_uri: 'https://app.com/callback',
+      scope: 'public',
+      nonce: '12345',
+    }
+
+    pre_auth = Doorkeeper::OAuth::PreAuthorization.new(server, attributes)
+    pre_auth.authorizable? # triggers loading of pre_auth.client
+    pre_auth
+  end
+
+  let(:owner) { build_stubbed(:user) }
+
+  # just to make sure self created pre_auth is authorizable
+  it 'pre_auth should be valid' do
+    expect(pre_auth).to be_authorizable
+  end
+
+  it 'creates an access token' do
+    expect do
+      subject.authorize
+    end.to change { Doorkeeper::AccessToken.count }.by(1)
+  end
+
+  it 'returns id_token response' do
+    expect(subject.authorize).to be_a(Doorkeeper::OAuth::IdTokenResponse)
+  end
+
+  context 'token reuse' do
+    it 'creates a new token if there are no matching tokens' do
+      allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
+      expect do
+        subject.authorize
+      end.to change { Doorkeeper::AccessToken.count }.by(1)
+    end
+
+    it 'creates a new token if scopes do not match' do
+      allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
+      create(:access_token, application_id: pre_auth.client.id,
+             resource_owner_id: owner.id, scopes: '')
+      expect do
+        subject.authorize
+      end.to change { Doorkeeper::AccessToken.count }.by(1)
+    end
+
+    it 'skips token creation if there is a matching one' do
+      allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
+      allow(application.scopes).to receive(:has_scopes?).and_return(true)
+      allow(application.scopes).to receive(:all?).and_return(true)
+
+      create(:access_token, application_id: pre_auth.client.id,
+             resource_owner_id: owner.id, scopes: 'public')
+
+      expect { subject.authorize }.not_to(change { Doorkeeper::AccessToken.count })
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_response_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_response_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0381f921b2e24c495293b41eca7b1344114ff9c1
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_response_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OAuth::IdTokenResponse do
+  subject { described_class.new(pre_auth, auth, id_token) }
+
+  let(:token) { create :access_token }
+  let(:application) do
+    create(:application, scopes: 'public')
+  end
+
+  let(:pre_auth) do
+    double(
+      :pre_auth,
+      client: application,
+      redirect_uri: 'http://tst.com/cb',
+      state: 'state',
+      scopes: Doorkeeper::OAuth::Scopes.from_string('public'),
+      error: nil,
+      authorizable?: true,
+      nonce: '12345'
+    )
+  end
+
+  let(:owner) { build_stubbed(:user) }
+
+  let(:auth) do
+    Doorkeeper::OAuth::Authorization::Token.new(pre_auth, owner).tap do |c|
+      if c.respond_to?(:issue_token!)
+        c.issue_token!
+      else
+        c.issue_token
+      end
+    end
+  end
+  let(:id_token) { Doorkeeper::OpenidConnect::IdToken.new(token, pre_auth) }
+
+  describe '#body' do
+    it 'return body response for id_token' do
+      expect(subject.body).to eq({
+        expires_in: auth.token.expires_in_seconds,
+        state: pre_auth.state,
+        id_token: id_token.as_jws_token
+      })
+    end
+  end
+
+  describe '#redirect_uri' do
+    it 'includes expires_in, id_token and state' do
+      expect(subject.redirect_uri).to include("#{pre_auth.redirect_uri}#expires_in=#{auth.token.expires_in_seconds}&" \
+        "state=#{pre_auth.state}&" \
+        "id_token=#{id_token.as_jws_token}")
+    end
+
+    it 'does not include access_token' do
+      expect(subject.redirect_uri).not_to include('access_token')
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_request_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..760459531c3e06161feb79a2c562908c35396a19
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_request_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OAuth::IdTokenTokenRequest do
+  subject do
+    described_class.new(pre_auth, owner)
+  end
+
+  let :application do
+    FactoryBot.create(:application, scopes: 'public')
+  end
+
+  let :pre_auth do
+    server = Doorkeeper.configuration
+    allow(server).to receive(:grant_flows).and_return(['implicit_oidc'])
+
+    client = Doorkeeper::OAuth::Client.new(application)
+
+    attributes = {
+      client_id: client.uid,
+      response_type: 'id_token token',
+      redirect_uri: 'https://app.com/callback',
+      scope: 'public',
+      nonce: '12345',
+    }
+
+    pre_auth = Doorkeeper::OAuth::PreAuthorization.new(server, attributes)
+    pre_auth.authorizable?
+    pre_auth
+  end
+
+  let(:owner) { build_stubbed(:user) }
+
+  # just to make sure self created pre_auth is authorizable
+  it 'pre_auth should be valid' do
+    expect(pre_auth).to be_authorizable
+  end
+
+  it 'creates an access token' do
+    expect do
+      subject.authorize
+    end.to change { Doorkeeper::AccessToken.count }.by(1)
+  end
+
+  it 'returns id_token token response' do
+    expect(subject.authorize).to be_a(Doorkeeper::OAuth::IdTokenTokenResponse)
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_response_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_response_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..56f7724e6f24ac62ef1d226f511daf2ab0724b69
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_response_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OAuth::IdTokenTokenResponse do
+  subject { described_class.new(pre_auth, auth, id_token) }
+
+  let(:token) { create :access_token }
+  let(:application) do
+    create(:application, scopes: 'public')
+  end
+  let(:pre_auth) do
+    double(
+      :pre_auth,
+      client: application,
+      redirect_uri: 'http://tst.com/cb',
+      state: 'state',
+      scopes: Doorkeeper::OAuth::Scopes.from_string('public'),
+      error: nil,
+      authorizable?: true,
+      nonce: '12345'
+    )
+  end
+  let(:owner) { build_stubbed(:user) }
+  let(:auth) do
+    Doorkeeper::OAuth::Authorization::Token.new(pre_auth, owner).tap do |c|
+      if c.respond_to?(:issue_token!)
+        c.issue_token!
+      else
+        c.issue_token
+      end
+    end
+  end
+  let(:id_token) { Doorkeeper::OpenidConnect::IdToken.new(token, pre_auth) }
+
+  describe '#body' do
+    it 'return body response for id_token and access_token' do
+      expect(subject.body).to eq({
+        expires_in: auth.token.expires_in_seconds,
+        state: pre_auth.state,
+        id_token: id_token.as_jws_token,
+        access_token: auth.token.token,
+        token_type: auth.token.token_type
+      })
+    end
+  end
+
+  describe '#redirect_uri' do
+    it 'includes id_token, info of access_token and state' do
+      expect(subject.redirect_uri).to include("#{pre_auth.redirect_uri}#expires_in=#{auth.token.expires_in_seconds}&" \
+        "state=#{pre_auth.state}&" \
+        "id_token=#{id_token.as_jws_token}&" \
+        "access_token=#{auth.token.token}&token_type=#{auth.token.token_type}")
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/password_access_token_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/password_access_token_request_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2c235e7523156be46764fe7416a07d1de1054e7a
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/password_access_token_request_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::OAuth::PasswordAccessTokenRequest do
+  if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.1')
+    subject { Doorkeeper::OAuth::PasswordAccessTokenRequest.new server, client, credentials, resource_owner, { nonce: '123456' } }
+  else
+    subject { Doorkeeper::OAuth::PasswordAccessTokenRequest.new server, client, resource_owner, { nonce: '123456' } }
+  end
+
+  let(:server) { double }
+  let(:client) { double }
+  let(:credentials) { }
+  let(:resource_owner) { create :user }
+  let(:token) { create :access_token }
+  let(:response) { Doorkeeper::OAuth::TokenResponse.new token }
+
+  describe '#initialize' do
+    it 'stores the nonce attribute' do
+      expect(subject.nonce).to eq '123456'
+    end
+  end
+
+  describe '#after_successful_response' do
+    it 'adds the ID token to the response' do
+      subject.instance_variable_set '@response', response
+      subject.instance_variable_set '@access_token', token
+      subject.send :after_successful_response
+
+      expect(response.id_token).to be_a Doorkeeper::OpenidConnect::IdToken
+      expect(response.id_token.nonce).to eq '123456'
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/pre_authorization_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/pre_authorization_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c9807a4691243e8c1beec064fae3005bb11ff8cc
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/pre_authorization_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::OAuth::PreAuthorization do
+  subject { Doorkeeper::OAuth::PreAuthorization.new server, attrs }
+
+  let(:server) { Doorkeeper.configuration }
+  let(:attrs) {}
+
+  describe '#initialize' do
+    context 'with nonce parameter' do
+      let(:attrs) { { nonce: '123456' } }
+
+      it 'stores the nonce attribute' do
+        expect(subject.nonce).to eq '123456'
+      end
+    end
+  end
+
+  describe '#error_response' do
+    context 'with response_type = code' do
+      let(:attrs) { { response_type: 'code', redirect_uri: 'client.com/callback' } }
+
+      it 'redirects to redirect_uri with query parameter' do
+        expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}\?/)
+      end
+    end
+
+    context 'with response_type = token' do
+      let(:attrs) { { response_type: 'token', redirect_uri: 'client.com/callback' } }
+
+      it 'redirects to redirect_uri with fragment' do
+        expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}#/)
+      end
+    end
+
+    context 'with response_type = id_token' do
+      let(:attrs) { { response_type: 'id_token', redirect_uri: 'client.com/callback' } }
+
+      it 'redirects to redirect_uri with fragment' do
+        expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}#/)
+      end
+    end
+
+    context 'with response_type = id_token token' do
+      let(:attrs) { { response_type: 'id_token token', redirect_uri: 'client.com/callback' } }
+
+      it 'redirects to redirect_uri with fragment' do
+        expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}#/)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/token_response_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/token_response_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3fb85a2ea718fc571489e8a747bab884f998d6b6
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/token_response_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::OAuth::TokenResponse do
+  subject { Doorkeeper::OAuth::TokenResponse.new token }
+
+  let(:token) { create :access_token }
+  let(:client) { Doorkeeper::OAuth::Client.new create(:application) }
+  let(:pre_auth) { Doorkeeper::OAuth::PreAuthorization.new(Doorkeeper.configuration, client_id: client.uid, nonce: '123456') }
+  let(:id_token) { Doorkeeper::OpenidConnect::IdToken.new token, pre_auth }
+
+  before do
+    pre_auth.valid? # triggers loading of pre_auth.client
+  end
+
+  describe '#body' do
+    before do
+      subject.id_token = id_token
+    end
+
+    context 'with the openid scope present' do
+      before do
+        token.scopes = 'openid email'
+      end
+
+      it 'adds the ID token to the response' do
+        expect(subject.body[:id_token]).to eq id_token.as_jws_token
+      end
+    end
+
+    context 'with the openid scope present but no id_token' do
+      before do
+        token.scopes = 'openid email'
+        subject.id_token = nil
+      end
+
+      it 'adds the ID token to the response' do
+        expect(subject.body[:id_token]).to be_truthy
+      end
+    end
+
+    context 'with the openid scope not present' do
+      before do
+        token.scopes = 'email'
+      end
+
+      it 'does not add the ID token to the response' do
+        expect(subject.body).not_to include :id_token
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/openid_connect_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/openid_connect_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..31a03afb663b0176379a1fb34101a93808e8f30b
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/openid_connect_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect do
+  describe '.signing_algorithm' do
+    it 'returns the signing_algorithm as an uppercase symbol' do
+      expect(subject.signing_algorithm).to eq :RS256
+    end
+  end
+
+  describe '.signing_key' do
+    it 'returns the private key as JWK instance' do
+      expect(subject.signing_key).to be_a ::JWT::JWK::KeyBase
+      expect(subject.signing_key.kid).to eq 'IqYwZo2cE6hsyhs48cU8QHH4GanKIx0S4Dc99kgTIMA'
+    end
+  end
+
+  describe '.signing_key_normalized' do
+    context 'when signing key is RSA' do
+      it 'returns the RSA public key parameters' do
+        expect(subject.signing_key_normalized).to eq(
+          :kty => 'RSA',
+          :kid => 'IqYwZo2cE6hsyhs48cU8QHH4GanKIx0S4Dc99kgTIMA',
+          :e => 'AQAB',
+          :n => 'sjdnSA6UWUQQHf6BLIkIEUhMRNBJC1NN_pFt1EJmEiI88GS0ceROO5B5Ooo9Y3QOWJ_n-u1uwTHBz0HCTN4wgArWd1TcqB5GQzQRP4eYnWyPfi4CfeqAHzQp-v4VwbcK0LW4FqtW5D0dtrFtI281FDxLhARzkhU2y7fuYhL8fVw5rUhE8uwvHRZ5CEZyxf7BSHxIvOZAAymhuzNLATt2DGkDInU1BmF75tEtBJAVLzWG_j4LPZh1EpSdfezqaXQlcy9PJi916UzTl0P7Yy-ulOdUsMlB6yo8qKTY1-AbZ5jzneHbGDU_O8QjYvii1WDmJ60t0jXicmOkGrOhruOptw'
+        )
+      end
+    end
+
+    context 'when signing key is EC' do
+      before { configure_ec }
+
+      it 'returns the EC public key parameters' do
+        expect(subject.signing_key_normalized).to eq(
+          :kty => 'EC',
+          :kid => 'dOx_AhaepicN2r2M-sxZhgkYZMCX7dYhPsNOw1ZiFnI',
+          :crv => 'P-521',
+          :x => 'AeYVvbl3zZcFCdE-0msqOowYODjzeXAhjsZKhdNjGlDREvko3UFOw6S43g-s8bvVBmBz3fCodEzFRYQqJVI4UFvF',
+          :y => 'AYJ7GYeBm_Fb6liN53xGASdbRSzF34h4BDSVYzjtQc7I-1LK17fwwS3VfQCJwaT6zX33HTrhR4VoUEUJHKwR3dNs'
+        )
+      end
+    end
+
+    context 'when signing key is HMAC' do
+      before { configure_hmac }
+
+      it 'returns the HMAC public key parameters' do
+        expect(subject.signing_key_normalized).to eq(
+          :kty => 'oct',
+          :kid => 'lyAW7LdxryFWQtLdgxZpOrI87APHrzJKgWLT0BkWVog'
+        )
+      end
+    end
+  end
+
+  describe 'registering grant flows' do
+    describe Doorkeeper::Request do
+      it 'uses the correct strategy for "id_token" response types' do
+        expect(described_class.authorization_strategy('id_token')).to eq(Doorkeeper::Request::IdToken)
+      end
+
+      it 'uses the correct strategy for "id_token token" response types' do
+        expect(described_class.authorization_strategy('id_token token')).to eq(Doorkeeper::Request::IdTokenToken)
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/routes_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/routes_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2f7c8b510a865e6d1d19f9e6da4d38512db36645
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/routes_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::Rails::Routes, type: :routing do
+  describe 'userinfo' do
+    it 'maps GET #show' do
+      expect(get: 'oauth/userinfo').to route_to(
+        controller: 'doorkeeper/openid_connect/userinfo',
+        action: 'show'
+      )
+    end
+
+    it 'maps POST #show' do
+      expect(post: 'oauth/userinfo').to route_to(
+        controller: 'doorkeeper/openid_connect/userinfo',
+        action: 'show'
+      )
+    end
+  end
+
+  describe 'discovery' do
+    it 'maps GET #provider' do
+      expect(get: '.well-known/openid-configuration').to route_to(
+        controller: 'doorkeeper/openid_connect/discovery',
+        action: 'provider'
+      )
+    end
+
+    it 'maps GET #webfinger' do
+      expect(get: '.well-known/webfinger').to route_to(
+        controller: 'doorkeeper/openid_connect/discovery',
+        action: 'webfinger'
+      )
+    end
+
+    it 'maps GET #keys' do
+      expect(get: 'oauth/discovery/keys').to route_to(
+        controller: 'doorkeeper/openid_connect/discovery',
+        action: 'keys'
+      )
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/user_info_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/user_info_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cf866b42d6188ea64d9398bd297eed4ff3e96ce8
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/user_info_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::UserInfo do
+  subject { described_class.new token }
+
+  let(:user) { create :user, name: 'Joe' }
+  let(:token) { create :access_token, resource_owner_id: user.id, scopes: scopes }
+  let(:scopes) { 'openid' }
+
+  describe '#claims' do
+    it 'returns all accessible claims' do
+      expect(subject.claims).to eq({
+        sub: user.id.to_s,
+        created_at: user.created_at.to_i,
+        variable_name: 'openid-name',
+        token_id: token.id,
+        both_responses: 'both',
+        user_info_response: 'user_info',
+      })
+    end
+
+    context 'with a grant for the profile scopes' do
+      let(:scopes) { 'openid profile' }
+
+      it 'returns additional profile claims' do
+        expect(subject.claims).to eq({
+          sub: user.id.to_s,
+          name: 'Joe',
+          created_at: user.created_at.to_i,
+          updated_at: user.updated_at.to_i,
+          variable_name: 'profile-name',
+          token_id: token.id,
+          both_responses: 'both',
+          user_info_response: 'user_info',
+        })
+      end
+    end
+  end
+
+  describe '#as_json' do
+    it 'returns claims with nil values and empty strings removed' do
+      allow(subject).to receive(:claims).and_return({
+        nil: nil,
+        empty: '',
+        blank: ' ',
+      })
+
+      expect(subject.as_json).to eq({
+        blank: ' '
+      })
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/models/access_grant_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/models/access_grant_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..43e9ef8db6bb723a0cc73e2c621f7d66262f239f
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/models/access_grant_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::AccessGrant do
+  subject { Doorkeeper::AccessGrant.new }
+
+  it 'has one openid_request' do
+    association = subject.class.reflect_on_association :openid_request
+
+    expect(association.options).to eq({
+      class_name: 'Doorkeeper::OpenidConnect::Request',
+      inverse_of: :access_grant,
+      foreign_key: "access_grant_id",
+      dependent: :delete,
+    })
+  end
+
+  it 'extends the base doorkeeper AccessGrant' do
+    expect(subject).to respond_to(:"openid_request=")
+  end
+
+  describe '#delete' do
+    it 'cascades to oauth_openid_requests' do
+      if Rails::VERSION::MAJOR >= 6
+        access_grant = create(:access_grant, application: create(:application))
+        create(:openid_request, access_grant: access_grant)
+
+        expect { access_grant.delete }
+          .to(change { Doorkeeper::OpenidConnect::Request.count }.by(-1))
+      else
+        skip <<-MSG.strip
+          Needs Rails 6 for foreign key support with sqlite3:
+          https://blog.bigbinary.com/2019/09/24/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3.html
+        MSG
+      end
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/models/request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/models/request_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4126fbd012335a6acac46dc8dc97d9a41e488eb4
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/models/request_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Doorkeeper::OpenidConnect::Request do
+  describe 'validations' do
+    it 'requires an access grant' do
+      subject.access_grant_id = nil
+
+      expect(subject).not_to be_valid
+      expect(subject.errors).to include :access_grant_id
+    end
+
+    it 'requires a nonce' do
+      subject.nonce = nil
+
+      expect(subject).not_to be_valid
+      expect(subject.errors).to include :nonce
+    end
+  end
+
+  describe 'associations' do
+    it 'belongs to an access_grant' do
+      association = subject.class.reflect_on_association :access_grant
+
+      expect(association.options).to eq({
+        class_name: 'Doorkeeper::AccessGrant',
+        inverse_of: :openid_request,
+      })
+    end
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/rails_helper.rb b/vendor/gems/doorkeeper-openid_connect/spec/rails_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..79b9c48543b37c08c0e8d24eb5732c438df51b27
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/rails_helper.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+# This file is copied to spec/ when you run 'rails generate rspec:install'
+ENV['RAILS_ENV'] ||= 'test'
+require 'dummy/config/environment'
+# Prevent database truncation if the environment is production
+abort('The Rails environment is running in production mode!') if Rails.env.production?
+require 'spec_helper'
+require 'rspec/rails'
+# Add additional requires below this line. Rails is not loaded until this point!
+
+# Requires supporting ruby files with custom matchers and macros, etc, in
+# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
+# run as spec files by default. This means that files in spec/support that end
+# in _spec.rb will both be required and run as specs, causing the specs to be
+# run twice. It is recommended that you do not name files matching this glob to
+# end with _spec.rb. You can configure this pattern with the --pattern
+# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
+#
+# The following line is provided for convenience purposes. It has the downside
+# of increasing the boot-up time by auto-requiring all files in the support
+# directory. Alternatively, in the individual `*_spec.rb` files, manually
+# require only the support files necessary.
+#
+# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
+
+# Checks for pending migration and applies them before tests are run.
+# If you are not using ActiveRecord, you can remove this line.
+Dir.chdir('spec/dummy') do
+  ActiveRecord::Migration.maintain_test_schema!
+end
+
+require_relative 'support/doorkeeper_configuration.rb'
+
+require 'factory_bot'
+FactoryBot.find_definitions
+
+RSpec.configure do |config|
+  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+  config.fixture_path = "#{::Rails.root}/spec/fixtures"
+
+  # If you're not using ActiveRecord, or you'd prefer not to run each of your
+  # examples within a transaction, remove the following line or assign false
+  # instead of true.
+  config.use_transactional_fixtures = true
+
+  # Filter lines from Rails gems in backtraces.
+  config.filter_rails_from_backtrace!
+  # arbitrary gems may also be filtered via:
+  # config.filter_gems_from_backtrace("gem name")
+
+  config.include FactoryBot::Syntax::Methods
+
+  # Reinitialize configuration after each example
+  config.after do
+    load Rails.root.join('config/initializers/doorkeeper.rb')
+    load Rails.root.join('config/initializers/doorkeeper_openid_connect.rb')
+  end
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/spec_helper.rb b/vendor/gems/doorkeeper-openid_connect/spec/spec_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b0b2a54d4b00225b066fc44a6fa99c27eb726873
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/spec_helper.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'pry-byebug'
+
+puts "====> Doorkeeper version: #{Doorkeeper::VERSION::STRING}"
+
+RSpec.configure do |config|
+  # rspec-expectations config goes here. You can use an alternate
+  # assertion/expectation library such as wrong or the stdlib/minitest
+  # assertions if you prefer.
+  config.expect_with :rspec do |expectations|
+    # This option will default to `true` in RSpec 4. It makes the `description`
+    # and `failure_message` of custom matchers include text for helper methods
+    # defined using `chain`, e.g.:
+    #     be_bigger_than(2).and_smaller_than(4).description
+    #     # => "be bigger than 2 and smaller than 4"
+    # ...rather than:
+    #     # => "be bigger than 2"
+    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+  end
+
+  # rspec-mocks config goes here. You can use an alternate test double
+  # library (such as bogus or mocha) by changing the `mock_with` option here.
+  config.mock_with :rspec do |mocks|
+    # Prevents you from mocking or stubbing a method that does not exist on
+    # a real object. This is generally recommended, and will default to
+    # `true` in RSpec 4.
+    mocks.verify_partial_doubles = true
+  end
+
+  # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
+  # have no way to turn it off -- the option exists only for backwards
+  # compatibility in RSpec 3). It causes shared context metadata to be
+  # inherited by the metadata hash of host groups and examples, rather than
+  # triggering implicit auto-inclusion in groups with matching metadata.
+  config.shared_context_metadata_behavior = :apply_to_host_groups
+
+  # The settings below are suggested to provide a good initial experience
+  # with RSpec, but feel free to customize to your heart's content.
+  # This allows you to limit a spec run to individual examples or groups
+  # you care about by tagging them with `:focus` metadata. When nothing
+  # is tagged with `:focus`, all examples get run. RSpec also provides
+  # aliases for `it`, `describe`, and `context` that include `:focus`
+  # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
+  config.filter_run_when_matching :focus
+
+  # Allows RSpec to persist some state between runs in order to support
+  # the `--only-failures` and `--next-failure` CLI options. We recommend
+  # you configure your source control system to ignore this file.
+  config.example_status_persistence_file_path = 'spec/examples.txt'
+
+  # Limits the available syntax to the non-monkey patched syntax that is
+  # recommended. For more details, see:
+  #   - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
+  #   - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+  #   - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
+  # config.disable_monkey_patching!
+
+  # Many RSpec users commonly either run the entire suite or an individual
+  # file, and it's useful to allow more verbose output when running an
+  # individual spec file.
+  if config.files_to_run.one?
+    # Use the documentation formatter for detailed output,
+    # unless a formatter has already been configured
+    # (e.g. via a command-line flag).
+    config.default_formatter = 'doc'
+  end
+
+  # Print the 10 slowest examples and example groups at the
+  # end of the spec run, to help surface which specs are running
+  # particularly slow.
+  # config.profile_examples = 10
+
+  # Run specs in random order to surface order dependencies. If you find an
+  # order dependency and want to debug it, you can fix the order by providing
+  # the seed, which is printed after each run.
+  #     --seed 1234
+  config.order = :random
+
+  # Seed global randomization in this process using the `--seed` CLI option.
+  # Setting this allows you to use `--seed` to deterministically reproduce
+  # test failures related to randomization by passing the same `--seed` value
+  # as the one that triggered the failure.
+  Kernel.srand config.seed
+end
diff --git a/vendor/gems/doorkeeper-openid_connect/spec/support/doorkeeper_configuration.rb b/vendor/gems/doorkeeper-openid_connect/spec/support/doorkeeper_configuration.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5198a0b35144351b9a6b523701065938c24b4230
--- /dev/null
+++ b/vendor/gems/doorkeeper-openid_connect/spec/support/doorkeeper_configuration.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module DoorkeeperConfiguration
+  def configure_doorkeeper(signing_key, signing_algorithm)
+    Doorkeeper::OpenidConnect.configure do
+      signing_key signing_key
+
+      signing_algorithm signing_algorithm
+
+      resource_owner_from_access_token do |access_token|
+        User.find_by(id: access_token.resource_owner_id)
+      end
+
+      auth_time_from_resource_owner do |resource_owner|
+        resource_owner.current_sign_in_at
+      end
+
+      subject do |resource_owner|
+        resource_owner.id
+      end
+    end
+  end
+
+  def configure_ec
+    signing_key = <<~EOL
+      -----BEGIN EC PRIVATE KEY-----
+      MIHbAgEBBEF9VcxGjPKczrJlE1N3oEpZsauQfDXIjLeini7h4/3+DOKw2VWE4lCU
+      rNJJL65EHT+2TriRg2xSb0l0rK/MAFAFraAHBgUrgQQAI6GBiQOBhgAEAeYVvbl3
+      zZcFCdE+0msqOowYODjzeXAhjsZKhdNjGlDREvko3UFOw6S43g+s8bvVBmBz3fCo
+      dEzFRYQqJVI4UFvFAYJ7GYeBm/Fb6liN53xGASdbRSzF34h4BDSVYzjtQc7I+1LK
+      17fwwS3VfQCJwaT6zX33HTrhR4VoUEUJHKwR3dNs
+      -----END EC PRIVATE KEY-----
+    EOL
+    configure_doorkeeper(signing_key, :ES512)
+  end
+
+  def configure_hmac
+    configure_doorkeeper('the_greatest_secret_key', :HS512)
+  end
+end
+
+RSpec.configure { |config| config.include DoorkeeperConfiguration }