standard_id 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/standard_id/api/oauth/registrations_controller.rb +91 -0
- data/app/controllers/standard_id/api/well_known/oauth_authorization_server_controller.rb +4 -1
- data/app/controllers/standard_id/api/well_known/openid_configuration_controller.rb +4 -1
- data/config/routes/api.rb +5 -0
- data/lib/standard_id/config/schema.rb +23 -0
- data/lib/standard_id/errors.rb +12 -0
- data/lib/standard_id/oauth/client_registration.rb +205 -0
- data/lib/standard_id/oauth/discovery_document.rb +4 -3
- data/lib/standard_id/version.rb +1 -1
- data/lib/standard_id.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7caed55f6e5f6f70b01a7e79dabdc5ad9ddd646535f8c10bbde93158c65e32d9
|
|
4
|
+
data.tar.gz: 7ca5e3b573b3718e722eb047f14eefffab20263ee374d23f706f278878bcc640
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c68adc74ec092631a1af808cc61ea1d2d8adeb72dbaa70588cd4069edd71b94d57e6ed33f5a9fc5ca4104def616b779e9bbe44f3c9b61e9a861ebdee1eadc946
|
|
7
|
+
data.tar.gz: 6f10a9a4916737e870798e38c96c53e7767fcf9c4e538bd5c0ca0ee43d21843ec3dff838ee384d1acb6d68336655165fc43cf970e3e8a4e65e5e75cba32fd51f
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module StandardId
|
|
2
|
+
module Api
|
|
3
|
+
module Oauth
|
|
4
|
+
# RFC 7591 Dynamic Client Registration endpoint (POST /oauth/register).
|
|
5
|
+
#
|
|
6
|
+
# The endpoint is fully absent (404) unless
|
|
7
|
+
# `StandardId.config.oauth.dynamic_registration_enabled` is true — an open,
|
|
8
|
+
# unauthenticated registration endpoint is state-mutating attack surface,
|
|
9
|
+
# so it is opt-in. When enabled, the controller stays thin: it parses the
|
|
10
|
+
# JSON client metadata and delegates the RFC 7591 -> ClientApplication
|
|
11
|
+
# mapping (and the engine's security defaults) to
|
|
12
|
+
# StandardId::Oauth::ClientRegistration.
|
|
13
|
+
class RegistrationsController < BaseController
|
|
14
|
+
public_controller
|
|
15
|
+
|
|
16
|
+
# Throttle the open, unauthenticated registration endpoint by IP so an
|
|
17
|
+
# enabled deployment can't be flooded with ClientApplication rows.
|
|
18
|
+
rate_limit to: StandardId.config.rate_limits.dynamic_registration_per_ip,
|
|
19
|
+
within: 1.hour,
|
|
20
|
+
name: "dynamic-registration-ip",
|
|
21
|
+
only: :create,
|
|
22
|
+
store: StandardId::RateLimitHandling::RATE_LIMIT_STORE
|
|
23
|
+
|
|
24
|
+
before_action :require_dynamic_registration_enabled!
|
|
25
|
+
|
|
26
|
+
# POST /oauth/register
|
|
27
|
+
def create
|
|
28
|
+
result = StandardId::Oauth::ClientRegistration.call(client_metadata)
|
|
29
|
+
render json: registration_response(result), status: :created
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Return 404 (not 403) when the feature is off so the endpoint is
|
|
35
|
+
# indistinguishable from one that does not exist.
|
|
36
|
+
def require_dynamic_registration_enabled!
|
|
37
|
+
head(:not_found) unless StandardId.config.oauth.dynamic_registration_enabled
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Permit the full RFC 7591 client metadata document. We hand the raw
|
|
41
|
+
# values to the service, which whitelists/maps them; the controller does
|
|
42
|
+
# not need typed param coercion here.
|
|
43
|
+
def client_metadata
|
|
44
|
+
params.permit(
|
|
45
|
+
:client_name,
|
|
46
|
+
:scope,
|
|
47
|
+
:token_endpoint_auth_method,
|
|
48
|
+
redirect_uris: [],
|
|
49
|
+
grant_types: [],
|
|
50
|
+
response_types: []
|
|
51
|
+
).to_h.tap do |permitted|
|
|
52
|
+
# `params.permit` drops scalars passed where an array was declared
|
|
53
|
+
# (and vice versa); fall back to the raw value so the service can
|
|
54
|
+
# accept either an array or a space-delimited string.
|
|
55
|
+
%i[redirect_uris grant_types response_types].each do |key|
|
|
56
|
+
permitted[key] = params[key] if permitted[key].blank? && params[key].present?
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# RFC 7591 §3.2.1 success response. Echoes the registered metadata and,
|
|
62
|
+
# for confidential clients, the one-time client_secret with
|
|
63
|
+
# client_secret_expires_at: 0 (never expires).
|
|
64
|
+
def registration_response(result)
|
|
65
|
+
client = result.client
|
|
66
|
+
|
|
67
|
+
body = {
|
|
68
|
+
client_id: client.client_id,
|
|
69
|
+
client_id_issued_at: client.created_at.to_i,
|
|
70
|
+
client_name: client.name,
|
|
71
|
+
redirect_uris: client.redirect_uris_array,
|
|
72
|
+
grant_types: client.grant_types_array,
|
|
73
|
+
response_types: client.response_types_array,
|
|
74
|
+
scope: client.scopes,
|
|
75
|
+
# Echo the registered value (RFC 7591 §3.2.1), not a value derived
|
|
76
|
+
# from client_type — both client_secret_basic and client_secret_post
|
|
77
|
+
# are accepted and both work at the token endpoint.
|
|
78
|
+
token_endpoint_auth_method: result.token_endpoint_auth_method
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if result.client_secret
|
|
82
|
+
body[:client_secret] = result.client_secret
|
|
83
|
+
body[:client_secret_expires_at] = 0
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
body
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -27,7 +27,10 @@ module StandardId
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
response.headers["Cache-Control"] = "public, max-age=3600"
|
|
30
|
-
render json: StandardId::Oauth::DiscoveryDocument.build(
|
|
30
|
+
render json: StandardId::Oauth::DiscoveryDocument.build(
|
|
31
|
+
issuer,
|
|
32
|
+
registration_enabled: StandardId.config.oauth.dynamic_registration_enabled
|
|
33
|
+
)
|
|
31
34
|
end
|
|
32
35
|
end
|
|
33
36
|
end
|
|
@@ -14,7 +14,10 @@ module StandardId
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
response.headers["Cache-Control"] = "public, max-age=3600"
|
|
17
|
-
render json: StandardId::Oauth::DiscoveryDocument.build(
|
|
17
|
+
render json: StandardId::Oauth::DiscoveryDocument.build(
|
|
18
|
+
issuer,
|
|
19
|
+
registration_enabled: StandardId.config.oauth.dynamic_registration_enabled
|
|
20
|
+
)
|
|
18
21
|
end
|
|
19
22
|
end
|
|
20
23
|
end
|
data/config/routes/api.rb
CHANGED
|
@@ -18,6 +18,11 @@ StandardId::ApiEngine.routes.draw do
|
|
|
18
18
|
resource :token, only: [:create]
|
|
19
19
|
resource :revoke, only: [:create], controller: :revocations
|
|
20
20
|
|
|
21
|
+
# RFC 7591 Dynamic Client Registration -> POST /oauth/register.
|
|
22
|
+
# The controller returns 404 when oauth.dynamic_registration_enabled is
|
|
23
|
+
# false, so the endpoint is fully absent unless explicitly enabled.
|
|
24
|
+
resource :register, only: [:create], controller: :registrations
|
|
25
|
+
|
|
21
26
|
namespace :callback do
|
|
22
27
|
post ":provider", to: "providers#callback", as: :provider
|
|
23
28
|
end
|
|
@@ -270,6 +270,25 @@ StandardId::ConfigSchema.define do
|
|
|
270
270
|
# Must return a Hash of custom claims to merge into the JWT payload.
|
|
271
271
|
# Example: ->(account:, **) { { channel_id: account.channel_id } }
|
|
272
272
|
field :custom_claims, type: :any, default: nil
|
|
273
|
+
|
|
274
|
+
# RFC 7591 Dynamic Client Registration.
|
|
275
|
+
#
|
|
276
|
+
# When false (the default), the registration endpoint is fully absent
|
|
277
|
+
# (`POST /oauth/register` returns 404) and `registration_endpoint` is NOT
|
|
278
|
+
# advertised in the discovery documents. An open, unauthenticated
|
|
279
|
+
# registration endpoint is state-mutating attack surface (anyone can mint
|
|
280
|
+
# OAuth clients), so it is opt-in: a deployment must explicitly turn it on.
|
|
281
|
+
field :dynamic_registration_enabled, type: :boolean, default: false
|
|
282
|
+
|
|
283
|
+
# Callable resolving the polymorphic owner assigned to clients created via
|
|
284
|
+
# Dynamic Client Registration (the `owner` association on ClientApplication
|
|
285
|
+
# is required). Example: `-> { Organization.default }`.
|
|
286
|
+
#
|
|
287
|
+
# When `dynamic_registration_enabled` is true but this resolver is nil (or
|
|
288
|
+
# returns nil), registration raises a clear configuration error rather than
|
|
289
|
+
# silently failing the model's presence validation — so misconfiguration is
|
|
290
|
+
# caught loudly at request time.
|
|
291
|
+
field :dynamic_registration_owner, type: :any, default: nil
|
|
273
292
|
end
|
|
274
293
|
|
|
275
294
|
scope :social do
|
|
@@ -308,5 +327,9 @@ StandardId::ConfigSchema.define do
|
|
|
308
327
|
field :api_passwordless_start_per_ip, type: :integer, default: 10 # per hour
|
|
309
328
|
field :api_passwordless_start_per_target, type: :integer, default: 5 # per 15 minutes
|
|
310
329
|
field :api_token_per_ip, type: :integer, default: 30 # per 15 minutes
|
|
330
|
+
|
|
331
|
+
# Dynamic client registration (RFC 7591) — throttle the open registration
|
|
332
|
+
# endpoint by IP so an enabled deployment can't be flooded with client rows.
|
|
333
|
+
field :dynamic_registration_per_ip, type: :integer, default: 10 # per hour
|
|
311
334
|
end
|
|
312
335
|
end
|
data/lib/standard_id/errors.rb
CHANGED
|
@@ -110,6 +110,18 @@ module StandardId
|
|
|
110
110
|
def oauth_error_code = :unsupported_response_type
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
+
# RFC 7591 §3.2.2 client registration errors. Both render as HTTP 400 with
|
|
114
|
+
# an `error` of `invalid_redirect_uri` / `invalid_client_metadata` and an
|
|
115
|
+
# `error_description`. They subclass OAuthError so the existing OAuth error
|
|
116
|
+
# handling renders them in the standard error shape.
|
|
117
|
+
class InvalidRedirectUriError < OAuthError
|
|
118
|
+
def oauth_error_code = :invalid_redirect_uri
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class InvalidClientMetadataError < OAuthError
|
|
122
|
+
def oauth_error_code = :invalid_client_metadata
|
|
123
|
+
end
|
|
124
|
+
|
|
113
125
|
# Lifecycle hook errors
|
|
114
126
|
class AuthenticationDenied < StandardError; end
|
|
115
127
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
require "securerandom"
|
|
2
|
+
|
|
3
|
+
module StandardId
|
|
4
|
+
module Oauth
|
|
5
|
+
# RFC 7591 Dynamic Client Registration.
|
|
6
|
+
#
|
|
7
|
+
# Maps a client metadata document (the JSON body of POST /oauth/register)
|
|
8
|
+
# onto a StandardId::ClientApplication, applying the engine's security
|
|
9
|
+
# defaults (PKCE-forced public clients, S256, consent-by-default) and a
|
|
10
|
+
# conservative whitelist of grant/response types. Keeps the controller thin
|
|
11
|
+
# in the same flow-object style as the other lib/standard_id/oauth/ objects.
|
|
12
|
+
#
|
|
13
|
+
# On success #call returns a Result carrying the persisted client plus the
|
|
14
|
+
# one-time plaintext secret (confidential clients only); on a metadata or
|
|
15
|
+
# redirect-uri problem it raises the matching RFC 7591 §3.2.2 error
|
|
16
|
+
# (InvalidRedirectUriError / InvalidClientMetadataError), which the
|
|
17
|
+
# controller renders as HTTP 400. A nil owner resolver while the feature is
|
|
18
|
+
# enabled raises ConfigurationError (a host-app bug, not client input).
|
|
19
|
+
class ClientRegistration
|
|
20
|
+
# RFC 7591 grant_types we support. M2M (client_credentials) is deliberately
|
|
21
|
+
# excluded from DCR — self-registered clients are public/interactive.
|
|
22
|
+
ALLOWED_GRANT_TYPES = %w[authorization_code refresh_token].freeze
|
|
23
|
+
# Only the authorization-code response type is supported.
|
|
24
|
+
ALLOWED_RESPONSE_TYPES = %w[code].freeze
|
|
25
|
+
# token_endpoint_auth_method -> client_type mapping.
|
|
26
|
+
PUBLIC_AUTH_METHOD = "none".freeze
|
|
27
|
+
CONFIDENTIAL_AUTH_METHODS = %w[client_secret_basic client_secret_post].freeze
|
|
28
|
+
DEFAULT_AUTH_METHOD = PUBLIC_AUTH_METHOD
|
|
29
|
+
DEFAULT_SCOPE = "openid profile email".freeze
|
|
30
|
+
|
|
31
|
+
# Minimal result object mirroring the gem's `result.success?` /
|
|
32
|
+
# `result.value` convention. `client_secret` is the one-time plaintext for
|
|
33
|
+
# confidential clients (nil for public clients).
|
|
34
|
+
Result = Struct.new(:client, :client_secret, :token_endpoint_auth_method, keyword_init: true) do
|
|
35
|
+
def success? = true
|
|
36
|
+
def value = client
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param metadata [Hash] RFC 7591 client metadata (symbolized or stringified keys)
|
|
40
|
+
def initialize(metadata)
|
|
41
|
+
@metadata = (metadata || {}).to_h.symbolize_keys
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.call(metadata)
|
|
45
|
+
new(metadata).call
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def call
|
|
49
|
+
attrs = mapped_attributes
|
|
50
|
+
client = StandardId::ClientApplication.new(attrs)
|
|
51
|
+
|
|
52
|
+
secret_plaintext = nil
|
|
53
|
+
StandardId::ClientApplication.transaction do
|
|
54
|
+
client.save!
|
|
55
|
+
if client.confidential?
|
|
56
|
+
secret_plaintext = SecureRandom.hex(32)
|
|
57
|
+
client.create_client_secret!(
|
|
58
|
+
name: "Dynamic Registration Secret",
|
|
59
|
+
client_secret: secret_plaintext
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
Result.new(client: client, client_secret: secret_plaintext, token_endpoint_auth_method: auth_method)
|
|
65
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
66
|
+
raise_for(e.record)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
attr_reader :metadata
|
|
72
|
+
|
|
73
|
+
def mapped_attributes
|
|
74
|
+
{
|
|
75
|
+
owner: resolve_owner!,
|
|
76
|
+
name: client_name,
|
|
77
|
+
redirect_uris: redirect_uris,
|
|
78
|
+
grant_types: grant_types,
|
|
79
|
+
response_types: response_types,
|
|
80
|
+
scopes: scope,
|
|
81
|
+
client_type: client_type,
|
|
82
|
+
require_pkce: require_pkce?,
|
|
83
|
+
code_challenge_methods: code_challenge_methods,
|
|
84
|
+
require_consent: true
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# redirect_uris is REQUIRED (RFC 7591 §2). We pass the raw value through to
|
|
89
|
+
# the model and let its redirect-uri validation surface an invalid_redirect_uri
|
|
90
|
+
# error — keeping a single source of truth for URI rules.
|
|
91
|
+
def redirect_uris
|
|
92
|
+
Array(metadata[:redirect_uris]).map { |u| u.to_s.strip }.reject(&:blank?).join(" ")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def client_name
|
|
96
|
+
name = metadata[:client_name].to_s.strip
|
|
97
|
+
name.presence || "Dynamically Registered Client #{SecureRandom.hex(4)}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Whitelist grant_types. Any value outside ALLOWED_GRANT_TYPES is rejected
|
|
101
|
+
# as invalid_client_metadata (RFC 7591 §3.2.2). Absent -> authorization_code.
|
|
102
|
+
def grant_types
|
|
103
|
+
requested = list_param(:grant_types)
|
|
104
|
+
return "authorization_code" if requested.empty?
|
|
105
|
+
|
|
106
|
+
disallowed = requested - ALLOWED_GRANT_TYPES
|
|
107
|
+
if disallowed.any?
|
|
108
|
+
raise StandardId::InvalidClientMetadataError,
|
|
109
|
+
"Unsupported grant_types: #{disallowed.join(', ')}. Allowed: #{ALLOWED_GRANT_TYPES.join(', ')}"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
requested.join(" ")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def response_types
|
|
116
|
+
requested = list_param(:response_types)
|
|
117
|
+
return "code" if requested.empty?
|
|
118
|
+
|
|
119
|
+
disallowed = requested - ALLOWED_RESPONSE_TYPES
|
|
120
|
+
if disallowed.any?
|
|
121
|
+
raise StandardId::InvalidClientMetadataError,
|
|
122
|
+
"Unsupported response_types: #{disallowed.join(', ')}. Allowed: #{ALLOWED_RESPONSE_TYPES.join(', ')}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
requested.join(" ")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def scope
|
|
129
|
+
scope = metadata[:scope].to_s.strip
|
|
130
|
+
scope.presence || DEFAULT_SCOPE
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def auth_method
|
|
134
|
+
method = metadata[:token_endpoint_auth_method].to_s.strip
|
|
135
|
+
method.presence || DEFAULT_AUTH_METHOD
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def client_type
|
|
139
|
+
method = auth_method
|
|
140
|
+
return "public" if method == PUBLIC_AUTH_METHOD
|
|
141
|
+
return "confidential" if CONFIDENTIAL_AUTH_METHODS.include?(method)
|
|
142
|
+
|
|
143
|
+
raise StandardId::InvalidClientMetadataError,
|
|
144
|
+
"Unsupported token_endpoint_auth_method: #{method.inspect}. " \
|
|
145
|
+
"Allowed: #{(CONFIDENTIAL_AUTH_METHODS + [PUBLIC_AUTH_METHOD]).join(', ')}"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Public clients are always forced onto PKCE/S256 (the model also validates
|
|
149
|
+
# this). Confidential clients also default to PKCE here for defense in depth.
|
|
150
|
+
def require_pkce?
|
|
151
|
+
true
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def code_challenge_methods
|
|
155
|
+
"S256"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def resolve_owner!
|
|
159
|
+
resolver = StandardId.config.oauth.dynamic_registration_owner
|
|
160
|
+
unless resolver.respond_to?(:call)
|
|
161
|
+
raise StandardId::ConfigurationError,
|
|
162
|
+
"oauth.dynamic_registration_owner must be set to a callable resolving the " \
|
|
163
|
+
"client owner when oauth.dynamic_registration_enabled is true " \
|
|
164
|
+
"(e.g. -> { Organization.default })"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
owner = resolver.call
|
|
168
|
+
if owner.nil?
|
|
169
|
+
raise StandardId::ConfigurationError,
|
|
170
|
+
"oauth.dynamic_registration_owner resolved to nil; it must return the " \
|
|
171
|
+
"polymorphic owner record for dynamically registered clients"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
owner
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Accept either an Array or a space-delimited String for list-shaped
|
|
178
|
+
# metadata fields (RFC 7591 uses JSON arrays; be lenient with strings too).
|
|
179
|
+
def list_param(key)
|
|
180
|
+
value = metadata[key]
|
|
181
|
+
case value
|
|
182
|
+
when Array
|
|
183
|
+
value.map { |v| v.to_s.strip }.reject(&:blank?)
|
|
184
|
+
else
|
|
185
|
+
value.to_s.split(/\s+/).map(&:strip).reject(&:blank?)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Translate an ActiveRecord validation failure into the matching RFC 7591
|
|
190
|
+
# error. A redirect_uris failure is invalid_redirect_uri; everything else
|
|
191
|
+
# (including a blank redirect_uris which the model reports as a presence
|
|
192
|
+
# error) maps to invalid_client_metadata.
|
|
193
|
+
def raise_for(record)
|
|
194
|
+
errors = record.errors
|
|
195
|
+
message = errors.full_messages.join("; ")
|
|
196
|
+
|
|
197
|
+
if errors.key?(:redirect_uris)
|
|
198
|
+
raise StandardId::InvalidRedirectUriError, message.presence || "Invalid redirect_uris"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
raise StandardId::InvalidClientMetadataError, message.presence || "Invalid client metadata"
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -20,9 +20,10 @@ module StandardId
|
|
|
20
20
|
|
|
21
21
|
# @param issuer [String] the configured issuer (e.g. "https://auth.example.com")
|
|
22
22
|
# @param registration_enabled [Boolean] when true, advertises the RFC 7591
|
|
23
|
-
# dynamic client registration endpoint.
|
|
24
|
-
#
|
|
25
|
-
#
|
|
23
|
+
# dynamic client registration endpoint. The well-known controllers pass
|
|
24
|
+
# `StandardId.config.oauth.dynamic_registration_enabled` here, so the
|
|
25
|
+
# `registration_endpoint` is emitted only when DCR is turned on. Defaults
|
|
26
|
+
# to false so callers (and tests) that omit it get no registration_endpoint.
|
|
26
27
|
# @return [Hash]
|
|
27
28
|
def build(issuer, registration_enabled: false)
|
|
28
29
|
base = issuer.to_s.chomp("/")
|
data/lib/standard_id/version.rb
CHANGED
data/lib/standard_id.rb
CHANGED
|
@@ -46,6 +46,7 @@ require "standard_id/oauth/subflows/social_login_grant"
|
|
|
46
46
|
require "standard_id/oauth/passwordless_otp_flow"
|
|
47
47
|
require "standard_id/oauth/discovery_document"
|
|
48
48
|
require "standard_id/oauth/consent_payload"
|
|
49
|
+
require "standard_id/oauth/client_registration"
|
|
49
50
|
require "standard_id/passwordless/base_strategy"
|
|
50
51
|
require "standard_id/passwordless/email_strategy"
|
|
51
52
|
require "standard_id/passwordless/sms_strategy"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: standard_id
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jaryl Sim
|
|
@@ -132,6 +132,7 @@ files:
|
|
|
132
132
|
- app/controllers/standard_id/api/base_controller.rb
|
|
133
133
|
- app/controllers/standard_id/api/oauth/base_controller.rb
|
|
134
134
|
- app/controllers/standard_id/api/oauth/callback/providers_controller.rb
|
|
135
|
+
- app/controllers/standard_id/api/oauth/registrations_controller.rb
|
|
135
136
|
- app/controllers/standard_id/api/oauth/revocations_controller.rb
|
|
136
137
|
- app/controllers/standard_id/api/oauth/tokens_controller.rb
|
|
137
138
|
- app/controllers/standard_id/api/oidc/logout_controller.rb
|
|
@@ -261,6 +262,7 @@ files:
|
|
|
261
262
|
- lib/standard_id/oauth/authorization_flow.rb
|
|
262
263
|
- lib/standard_id/oauth/base_request_flow.rb
|
|
263
264
|
- lib/standard_id/oauth/client_credentials_flow.rb
|
|
265
|
+
- lib/standard_id/oauth/client_registration.rb
|
|
264
266
|
- lib/standard_id/oauth/consent_payload.rb
|
|
265
267
|
- lib/standard_id/oauth/discovery_document.rb
|
|
266
268
|
- lib/standard_id/oauth/implicit_authorization_flow.rb
|