# Doorkeeper for OAuth2
gem "doorkeeper"
gem "doorkeeper-i18n"
+gem "doorkeeper-openid_connect"
# Markdown formatting support
gem "kramdown"
railties (>= 5)
doorkeeper-i18n (5.2.6)
doorkeeper (>= 5.2)
+ doorkeeper-openid_connect (1.8.7)
+ doorkeeper (>= 5.5, < 5.7)
+ jwt (>= 2.5)
dry-configurable (1.1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
delayed_job_active_record
doorkeeper
doorkeeper-i18n
+ doorkeeper-openid_connect
erb_lint
factory_bot_rails
faraday
--- /dev/null
+# 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
--- /dev/null
+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.'
OpenStreetMap::Application.routes.draw do
+ use_doorkeeper_openid_connect
use_doorkeeper :scope => "oauth2" do
controllers :authorizations => "oauth2_authorizations",
:applications => "oauth2_applications",
--- /dev/null
+class CreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration[7.0]
+ def change
+ create_table :oauth_openid_requests do |t|
+ t.references :access_grant, :null => false, :index => true
+ t.string :nonce, :null => false
+ end
+
+ # Avoid validating foreign keys doe to possible deadlock
+ # create a separate migration instead, as suggested by db:migrate
+
+ add_foreign_key(
+ :oauth_openid_requests,
+ :oauth_access_grants,
+ :column => :access_grant_id,
+ :on_delete => :cascade, :validate => false
+ )
+ end
+end
--- /dev/null
+class ValidateCreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration[7.0]
+ # Validate foreign key created by CreateDoorkeeperOpenidConnectTables
+ def change
+ validate_foreign_key :oauth_openid_requests, :oauth_access_grants
+ end
+end
ALTER SEQUENCE public.oauth_nonces_id_seq OWNED BY public.oauth_nonces.id;
+--
+-- Name: oauth_openid_requests; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.oauth_openid_requests (
+ id bigint NOT NULL,
+ access_grant_id bigint NOT NULL,
+ nonce character varying NOT NULL
+);
+
+
+--
+-- Name: oauth_openid_requests_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE public.oauth_openid_requests_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+--
+-- Name: oauth_openid_requests_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE public.oauth_openid_requests_id_seq OWNED BY public.oauth_openid_requests.id;
+
+
--
-- Name: oauth_tokens; Type: TABLE; Schema: public; Owner: -
--
ALTER TABLE ONLY public.oauth_nonces ALTER COLUMN id SET DEFAULT nextval('public.oauth_nonces_id_seq'::regclass);
+--
+-- Name: oauth_openid_requests id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.oauth_openid_requests ALTER COLUMN id SET DEFAULT nextval('public.oauth_openid_requests_id_seq'::regclass);
+
+
--
-- Name: oauth_tokens id; Type: DEFAULT; Schema: public; Owner: -
--
ADD CONSTRAINT oauth_nonces_pkey PRIMARY KEY (id);
+--
+-- Name: oauth_openid_requests oauth_openid_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.oauth_openid_requests
+ ADD CONSTRAINT oauth_openid_requests_pkey PRIMARY KEY (id);
+
+
--
-- Name: oauth_tokens oauth_tokens_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_oauth_nonces_on_nonce_and_timestamp ON public.oauth_nonces USING btree (nonce, "timestamp");
+--
+-- Name: index_oauth_openid_requests_on_access_grant_id; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_oauth_openid_requests_on_access_grant_id ON public.oauth_openid_requests USING btree (access_grant_id);
+
+
--
-- Name: index_oauth_tokens_on_token; Type: INDEX; Schema: public; Owner: -
--
ADD CONSTRAINT fk_rails_732cb83ab7 FOREIGN KEY (application_id) REFERENCES public.oauth_applications(id) NOT VALID;
+--
+-- Name: oauth_openid_requests fk_rails_77114b3b09; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.oauth_openid_requests
+ ADD CONSTRAINT fk_rails_77114b3b09 FOREIGN KEY (access_grant_id) REFERENCES public.oauth_access_grants(id) ON DELETE CASCADE;
+
+
--
-- Name: active_storage_variant_records fk_rails_993965df05; Type: FK CONSTRAINT; Schema: public; Owner: -
--
('20220223140543'),
('20230816135800'),
('20230825162137'),
+('20230830115219'),
+('20230830115220'),
('21'),
('22'),
('23'),