standard_id 0.48.0 → 0.49.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +178 -1
  4. data/app/controllers/concerns/standard_id/resource_server.rb +138 -0
  5. data/app/controllers/standard_id/api/authorization_controller.rb +1 -0
  6. data/app/controllers/standard_id/api/oauth/callback/providers_controller.rb +23 -0
  7. data/app/controllers/standard_id/api/oauth/registrations_controller.rb +99 -22
  8. data/app/controllers/standard_id/api/well_known/oauth_protected_resource_controller.rb +46 -0
  9. data/app/jobs/standard_id/cleanup_all_job.rb +4 -3
  10. data/app/jobs/standard_id/purge_stale_dynamic_clients_job.rb +73 -0
  11. data/app/models/standard_id/client_application.rb +38 -0
  12. data/config/routes/api.rb +9 -0
  13. data/db/migrate/20261020120000_add_registration_access_token_digest_to_standard_id_client_applications.rb +14 -0
  14. data/lib/generators/standard_id/install/install_generator.rb +2 -1
  15. data/lib/standard_id/config/callable_validator.rb +20 -0
  16. data/lib/standard_id/config/schema.rb +87 -0
  17. data/lib/standard_id/errors.rb +22 -0
  18. data/lib/standard_id/oauth/audience_resolver.rb +88 -0
  19. data/lib/standard_id/oauth/authorization_code_authorization_flow.rb +1 -1
  20. data/lib/standard_id/oauth/authorization_code_flow.rb +3 -1
  21. data/lib/standard_id/oauth/authorization_flow.rb +21 -1
  22. data/lib/standard_id/oauth/client_registration.rb +151 -23
  23. data/lib/standard_id/oauth/direct_mint_flow.rb +128 -0
  24. data/lib/standard_id/oauth/implicit_authorization_flow.rb +1 -1
  25. data/lib/standard_id/oauth/protected_resource_document.rb +171 -0
  26. data/lib/standard_id/oauth/refresh_token_flow.rb +1 -1
  27. data/lib/standard_id/otp.rb +9 -1
  28. data/lib/standard_id/passwordless/base_strategy.rb +4 -2
  29. data/lib/standard_id/routing.rb +21 -0
  30. data/lib/standard_id/token_minter.rb +74 -0
  31. data/lib/standard_id/version.rb +1 -1
  32. data/lib/standard_id.rb +4 -0
  33. data/lib/tasks/standard_id_tasks.rake +8 -1
  34. metadata +9 -1
@@ -0,0 +1,74 @@
1
+ module StandardId
2
+ # Mint an access token (and optionally a refresh token) for an account the
3
+ # host has already authenticated, through the same pipeline /oauth/token
4
+ # uses — so the claims, the audience → profile binding, the account-status
5
+ # guards and the OAUTH_TOKEN_ISSUING / OAUTH_TOKEN_ISSUED events are the ones
6
+ # every other token gets, instead of a hand-rolled JwtService.encode that
7
+ # re-derives the initializer's claim resolvers by hand.
8
+ #
9
+ # result = StandardId::TokenMinter.mint(
10
+ # account: account,
11
+ # audience: "harness",
12
+ # scopes: "profile permissions",
13
+ # grant_type: "harness.mint", # free-form; lands in the JWT and the audit event
14
+ # claims: { permissions: scopes }, # host extras; reserved keys are dropped
15
+ # expires_in: 60.minutes
16
+ # )
17
+ # result.access_token # the JWT
18
+ # result.jti # what OAUTH_TOKEN_ISSUED carried
19
+ #
20
+ # What runs, in order: audience validation (oauth.allowed_audiences),
21
+ # audience → profile binding (oauth.audience_profile_types, fail-closed),
22
+ # OAUTH_TOKEN_ISSUING (AccountStatus / AccountLocking refuse here),
23
+ # scope_claims + claim_resolvers and custom_claims, then the host's own
24
+ # +claims+, then OAUTH_TOKEN_ISSUED. A refresh token is persisted only when
25
+ # +refresh_token: true+, bound to +client_id+'s ClientApplication when that
26
+ # names one. Pass +request:+ to let config.session.session_type_resolver
27
+ # materialise a session; without it the mint is sessionless.
28
+ #
29
+ # Raises the same errors the token endpoint would (InvalidGrantError,
30
+ # InvalidRequestError, NoBoundProfileError, AccountDeactivatedError, …).
31
+ module TokenMinter
32
+ Result = Data.define(:access_token, :refresh_token, :token_type, :expires_in, :scope, :jti)
33
+
34
+ module_function
35
+
36
+ # @param account [ActiveRecord::Base] a persisted account
37
+ # @param audience [String, Array<String>] the `aud` claim
38
+ # @param grant_type [String] recorded in the JWT and the audit events
39
+ # @param scopes [String, Array<String>, nil] the `scope` claim and the key
40
+ # into oauth.scope_claims
41
+ # @param client_id [String, nil] the `client_id` claim; a registered
42
+ # ClientApplication's id binds the refresh token to it
43
+ # @param claims [Hash] extra claims merged last (reserved keys dropped)
44
+ # @param expires_in [Integer, ActiveSupport::Duration, nil] access-token
45
+ # lifetime; default is oauth.token_lifetimes[grant_type] or
46
+ # oauth.default_token_lifetime
47
+ # @param refresh_token [Boolean] also persist and return a refresh token;
48
+ # requires +client_id+, which the refresh grant matches on redemption
49
+ # @param request [ActionDispatch::Request, nil] lets session_type_resolver
50
+ # persist a session; resolvers see `request: nil` without it
51
+ # @param auth_method [Symbol, String, nil] how the host authenticated the
52
+ # account, recorded on the refresh token for login_method_policy; nil is
53
+ # judged as :unspecified on refresh, which a restrictive policy refuses
54
+ # @param auth_provider [String, nil]
55
+ # @return [Result]
56
+ def mint(account:, audience:, grant_type:, scopes: nil, client_id: nil, claims: {}, expires_in: nil,
57
+ refresh_token: false, request: nil, auth_method: nil, auth_provider: nil)
58
+ flow = StandardId::Oauth::DirectMintFlow.new(
59
+ account: account, audience: audience, grant_type: grant_type, scopes: scopes, client_id: client_id,
60
+ claims: claims, expires_in: expires_in, refresh_token: refresh_token, request: request,
61
+ auth_method: auth_method, auth_provider: auth_provider
62
+ )
63
+ response = flow.execute
64
+ Result.new(
65
+ access_token: response[:access_token],
66
+ refresh_token: response[:refresh_token],
67
+ token_type: response[:token_type],
68
+ expires_in: response[:expires_in],
69
+ scope: response[:scope],
70
+ jti: flow.issued_jti
71
+ )
72
+ end
73
+ end
74
+ end
@@ -1,3 +1,3 @@
1
1
  module StandardId
2
- VERSION = "0.48.0"
2
+ VERSION = "0.49.0"
3
3
  end
data/lib/standard_id.rb CHANGED
@@ -38,6 +38,7 @@ require "standard_id/auth_lineage"
38
38
  require "standard_id/account_cleanup"
39
39
  require "standard_id/oauth/audience_profile_resolver"
40
40
  require "standard_id/oauth/audience_scope_resolver"
41
+ require "standard_id/oauth/audience_resolver"
41
42
  require "standard_id/oauth/base_request_flow"
42
43
  require "standard_id/oauth/token_lifetime_resolver"
43
44
  require "standard_id/oauth/oauth_session_persistence"
@@ -47,6 +48,8 @@ require "standard_id/oauth/authorization_code_flow"
47
48
  require "standard_id/oauth/password_flow"
48
49
  require "standard_id/oauth/refresh_token_flow"
49
50
  require "standard_id/oauth/social_flow"
51
+ require "standard_id/oauth/direct_mint_flow"
52
+ require "standard_id/token_minter"
50
53
  require "standard_id/oauth/authorization_flow"
51
54
  require "standard_id/oauth/authorization_code_authorization_flow"
52
55
  require "standard_id/oauth/implicit_authorization_flow"
@@ -57,6 +60,7 @@ require "standard_id/oauth/passwordless_otp_flow"
57
60
  require "standard_id/oauth/discovery_resolver"
58
61
  require "standard_id/oauth/grant_types"
59
62
  require "standard_id/oauth/discovery_document"
63
+ require "standard_id/oauth/protected_resource_document"
60
64
  require "standard_id/routing"
61
65
  require "standard_id/oauth/consent_payload"
62
66
  require "standard_id/oauth/client_registration"
@@ -39,8 +39,15 @@ namespace :standard_id do
39
39
  )
40
40
  end
41
41
 
42
+ desc "Delete dynamically registered clients that were deregistered, or never authorized, more than GRACE_DAYS ago (default 7)"
43
+ task dynamic_clients: :environment do
44
+ StandardId::PurgeStaleDynamicClientsJob.perform_now(
45
+ stale_after_seconds: StandardId::RakeHelpers.grace_period_seconds
46
+ )
47
+ end
48
+
42
49
  desc "Run all StandardId cleanup jobs with GRACE_DAYS (default 7)"
43
- task all: [:sessions, :refresh_tokens, :authorization_codes, :code_challenges]
50
+ task all: [:sessions, :refresh_tokens, :authorization_codes, :code_challenges, :dynamic_clients]
44
51
  end
45
52
  end
46
53
 
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.48.0
4
+ version: 0.49.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaryl Sim
@@ -123,6 +123,7 @@ files:
123
123
  - app/controllers/concerns/standard_id/passwordless_flow.rb
124
124
  - app/controllers/concerns/standard_id/passwordless_strategy.rb
125
125
  - app/controllers/concerns/standard_id/rate_limit_handling.rb
126
+ - app/controllers/concerns/standard_id/resource_server.rb
126
127
  - app/controllers/concerns/standard_id/sentry_context.rb
127
128
  - app/controllers/concerns/standard_id/set_current_request_details.rb
128
129
  - app/controllers/concerns/standard_id/social_authentication.rb
@@ -143,6 +144,7 @@ files:
143
144
  - app/controllers/standard_id/api/userinfo_controller.rb
144
145
  - app/controllers/standard_id/api/well_known/jwks_controller.rb
145
146
  - app/controllers/standard_id/api/well_known/oauth_authorization_server_controller.rb
147
+ - app/controllers/standard_id/api/well_known/oauth_protected_resource_controller.rb
146
148
  - app/controllers/standard_id/api/well_known/openid_configuration_controller.rb
147
149
  - app/controllers/standard_id/web/account_controller.rb
148
150
  - app/controllers/standard_id/web/auth/callback/providers_controller.rb
@@ -172,6 +174,7 @@ files:
172
174
  - app/jobs/standard_id/cleanup_expired_refresh_tokens_job.rb
173
175
  - app/jobs/standard_id/cleanup_expired_sessions_job.rb
174
176
  - app/jobs/standard_id/password_reset_delivery_job.rb
177
+ - app/jobs/standard_id/purge_stale_dynamic_clients_job.rb
175
178
  - app/jobs/standard_id/secure_mail_delivery_job.rb
176
179
  - app/mailers/standard_id/application_mailer.rb
177
180
  - app/mailers/standard_id/password_reset_mailer.rb
@@ -239,6 +242,7 @@ files:
239
242
  - db/migrate/20261002000000_create_standard_id_social_identities.rb
240
243
  - db/migrate/20261004000000_add_auth_method_to_standard_id_refresh_tokens.rb
241
244
  - db/migrate/20261020000000_add_client_application_id_to_standard_id_refresh_tokens.rb
245
+ - db/migrate/20261020120000_add_registration_access_token_digest_to_standard_id_client_applications.rb
242
246
  - lib/generators/standard_id/install/install_generator.rb
243
247
  - lib/generators/standard_id/install/templates/standard_id.rb
244
248
  - lib/standard_id.rb
@@ -278,6 +282,7 @@ files:
278
282
  - lib/standard_id/migration_check.rb
279
283
  - lib/standard_id/migration_helpers.rb
280
284
  - lib/standard_id/oauth/audience_profile_resolver.rb
285
+ - lib/standard_id/oauth/audience_resolver.rb
281
286
  - lib/standard_id/oauth/audience_scope_resolver.rb
282
287
  - lib/standard_id/oauth/authorization_code_authorization_flow.rb
283
288
  - lib/standard_id/oauth/authorization_code_flow.rb
@@ -286,6 +291,7 @@ files:
286
291
  - lib/standard_id/oauth/client_credentials_flow.rb
287
292
  - lib/standard_id/oauth/client_registration.rb
288
293
  - lib/standard_id/oauth/consent_payload.rb
294
+ - lib/standard_id/oauth/direct_mint_flow.rb
289
295
  - lib/standard_id/oauth/discovery_document.rb
290
296
  - lib/standard_id/oauth/discovery_resolver.rb
291
297
  - lib/standard_id/oauth/grant_types.rb
@@ -293,6 +299,7 @@ files:
293
299
  - lib/standard_id/oauth/oauth_session_persistence.rb
294
300
  - lib/standard_id/oauth/password_flow.rb
295
301
  - lib/standard_id/oauth/passwordless_otp_flow.rb
302
+ - lib/standard_id/oauth/protected_resource_document.rb
296
303
  - lib/standard_id/oauth/refresh_token_flow.rb
297
304
  - lib/standard_id/oauth/social_flow.rb
298
305
  - lib/standard_id/oauth/subflows/base.rb
@@ -324,6 +331,7 @@ files:
324
331
  - lib/standard_id/testing/factory_bot.rb
325
332
  - lib/standard_id/testing/provider_examples.rb
326
333
  - lib/standard_id/testing/request_helpers.rb
334
+ - lib/standard_id/token_minter.rb
327
335
  - lib/standard_id/utils/callable_parameter_filter.rb
328
336
  - lib/standard_id/utils/ip_normalizer.rb
329
337
  - lib/standard_id/version.rb