token_authority 0.1.0 → 0.2.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +199 -7
  4. data/app/controllers/concerns/token_authority/client_authentication.rb +141 -0
  5. data/app/controllers/concerns/token_authority/controller_event_logging.rb +98 -0
  6. data/app/controllers/concerns/token_authority/initial_access_token_authentication.rb +35 -0
  7. data/app/controllers/concerns/token_authority/token_authentication.rb +128 -0
  8. data/app/controllers/token_authority/authorization_grants_controller.rb +119 -0
  9. data/app/controllers/token_authority/authorizations_controller.rb +105 -0
  10. data/app/controllers/token_authority/clients_controller.rb +99 -0
  11. data/app/controllers/token_authority/metadata_controller.rb +12 -0
  12. data/app/controllers/token_authority/resource_metadata_controller.rb +12 -0
  13. data/app/controllers/token_authority/sessions_controller.rb +228 -0
  14. data/app/helpers/token_authority/authorization_grants_helper.rb +27 -0
  15. data/app/models/concerns/token_authority/claim_validatable.rb +95 -0
  16. data/app/models/concerns/token_authority/event_logging.rb +144 -0
  17. data/app/models/concerns/token_authority/resourceable.rb +111 -0
  18. data/app/models/concerns/token_authority/scopeable.rb +105 -0
  19. data/app/models/concerns/token_authority/session_creatable.rb +101 -0
  20. data/app/models/token_authority/access_token.rb +127 -0
  21. data/app/models/token_authority/access_token_request.rb +193 -0
  22. data/app/models/token_authority/authorization_grant.rb +119 -0
  23. data/app/models/token_authority/authorization_request.rb +276 -0
  24. data/app/models/token_authority/authorization_server_metadata.rb +101 -0
  25. data/app/models/token_authority/client.rb +263 -0
  26. data/app/models/token_authority/client_id_resolver.rb +114 -0
  27. data/app/models/token_authority/client_metadata_document.rb +164 -0
  28. data/app/models/token_authority/client_metadata_document_cache.rb +33 -0
  29. data/app/models/token_authority/client_metadata_document_fetcher.rb +266 -0
  30. data/app/models/token_authority/client_registration_request.rb +214 -0
  31. data/app/models/token_authority/client_registration_response.rb +58 -0
  32. data/app/models/token_authority/jwks_cache.rb +37 -0
  33. data/app/models/token_authority/jwks_fetcher.rb +70 -0
  34. data/app/models/token_authority/protected_resource_metadata.rb +74 -0
  35. data/app/models/token_authority/refresh_token.rb +110 -0
  36. data/app/models/token_authority/refresh_token_request.rb +116 -0
  37. data/app/models/token_authority/session.rb +193 -0
  38. data/app/models/token_authority/software_statement.rb +70 -0
  39. data/app/views/token_authority/authorization_grants/new.html.erb +25 -0
  40. data/app/views/token_authority/client_error.html.erb +8 -0
  41. data/config/locales/token_authority.en.yml +248 -0
  42. data/config/routes.rb +29 -0
  43. data/lib/generators/token_authority/install/install_generator.rb +61 -0
  44. data/lib/generators/token_authority/install/templates/create_token_authority_tables.rb.erb +116 -0
  45. data/lib/generators/token_authority/install/templates/token_authority.rb +247 -0
  46. data/lib/token_authority/configuration.rb +397 -0
  47. data/lib/token_authority/engine.rb +34 -0
  48. data/lib/token_authority/errors.rb +221 -0
  49. data/lib/token_authority/instrumentation.rb +80 -0
  50. data/lib/token_authority/instrumentation_log_subscriber.rb +62 -0
  51. data/lib/token_authority/json_web_token.rb +78 -0
  52. data/lib/token_authority/log_event_subscriber.rb +43 -0
  53. data/lib/token_authority/routing/constraints.rb +71 -0
  54. data/lib/token_authority/routing/routes.rb +39 -0
  55. data/lib/token_authority/version.rb +4 -1
  56. data/lib/token_authority.rb +30 -1
  57. metadata +65 -5
  58. data/app/assets/stylesheets/token_authority/application.css +0 -15
  59. data/app/controllers/token_authority/application_controller.rb +0 -4
  60. data/app/helpers/token_authority/application_helper.rb +0 -4
  61. data/app/views/layouts/token_authority/application.html.erb +0 -17
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ TokenAuthority.configure do |config|
4
+ # ==========================================================================
5
+ # General
6
+ # ==========================================================================
7
+
8
+ # The secret key used for signing JWT tokens and generating client secrets.
9
+ # This should be a secure, random string. By default, it uses the application's
10
+ # secret_key_base from credentials or configuration.
11
+ config.secret_key = Rails.application.credentials.secret_key_base || Rails.application.secret_key_base
12
+
13
+ # ==========================================================================
14
+ # JWT Access Tokens (RFC 9068)
15
+ # ==========================================================================
16
+
17
+ # The audience URL for JWT tokens. This is typically your API's base URL.
18
+ # Used as the "aud" (audience) claim in issued tokens.
19
+ config.rfc_9068_audience_url = ENV.fetch("TOKEN_AUTHORITY_AUDIENCE_URL", "http://localhost:3000/api/")
20
+
21
+ # The issuer URL for JWT tokens. This is typically your application's base URL.
22
+ # Used as the "iss" (issuer) claim in issued tokens.
23
+ config.rfc_9068_issuer_url = ENV.fetch("TOKEN_AUTHORITY_ISSUER_URL", "http://localhost:3000/")
24
+
25
+ # Default duration for access tokens in seconds (5 minutes).
26
+ # This value is used when creating new clients without explicit durations.
27
+ # config.rfc_9068_default_access_token_duration = 300
28
+
29
+ # Default duration for refresh tokens in seconds (14 days).
30
+ # This value is used when creating new clients without explicit durations.
31
+ # config.rfc_9068_default_refresh_token_duration = 1_209_600
32
+
33
+ # ==========================================================================
34
+ # User Authentication
35
+ # ==========================================================================
36
+
37
+ # The authenticatable controller for the authorization grants controller (consent screen).
38
+ # This controller must implement:
39
+ # - authenticate_user! (before_action that ensures user is logged in)
40
+ # - current_user (returns the currently authenticated user)
41
+ #
42
+ # For Devise users, ApplicationController already has these methods.
43
+ # For other authentication systems, either:
44
+ # 1. Implement these methods on ApplicationController, or
45
+ # 2. Set this to a controller that provides these methods
46
+ # Default: "ApplicationController"
47
+ # config.authenticatable_controller = "ApplicationController"
48
+
49
+ # The class name of your user model. This is used for the belongs_to association
50
+ # in TokenAuthority::AuthorizationGrant.
51
+ # Default: "User"
52
+ # config.user_class = "User"
53
+
54
+ # ==========================================================================
55
+ # UI/Layout
56
+ # ==========================================================================
57
+
58
+ # The layout used for the OAuth consent screen.
59
+ config.consent_page_layout = "application"
60
+
61
+ # The layout used for error pages (e.g., invalid redirect URL).
62
+ config.error_page_layout = "application"
63
+
64
+ # ==========================================================================
65
+ # Server Metadata (RFC 8414)
66
+ # ==========================================================================
67
+
68
+ # URL to developer documentation for your OAuth server.
69
+ # Included in the /.well-known/oauth-authorization-server response.
70
+ # config.rfc_8414_service_documentation = "https://example.com/docs/oauth"
71
+
72
+ # Note: scopes_supported in the metadata response is automatically derived
73
+ # from the keys of config.scopes (see Scopes section below).
74
+
75
+ # ==========================================================================
76
+ # Protected Resource Metadata (RFC 9728)
77
+ # ==========================================================================
78
+
79
+ # The protected resource's identifier URL.
80
+ # Defaults to rfc_9068_issuer_url if not set.
81
+ # config.rfc_9728_resource = "https://api.example.com/"
82
+
83
+ # Scopes accepted by the protected resource.
84
+ # Falls back to config.scopes keys if not set.
85
+ # config.rfc_9728_scopes_supported = ["api:read", "api:write"]
86
+
87
+ # List of authorization server issuer URLs that can issue tokens for this resource.
88
+ # Defaults to the local authorization server (rfc_9068_issuer_url) if not set.
89
+ # config.rfc_9728_authorization_servers = ["https://auth.example.com"]
90
+
91
+ # Token presentation methods supported by the resource (e.g., "header", "body", "query").
92
+ # config.rfc_9728_bearer_methods_supported = ["header"]
93
+
94
+ # URL to the resource's JSON Web Key Set (JWKS).
95
+ # config.rfc_9728_jwks_uri = "https://api.example.com/.well-known/jwks.json"
96
+
97
+ # Human-readable name for the protected resource.
98
+ # config.rfc_9728_resource_name = "Example API"
99
+
100
+ # URL to developer documentation for the protected resource.
101
+ # config.rfc_9728_resource_documentation = "https://example.com/docs/api"
102
+
103
+ # URL to the resource's privacy policy.
104
+ # config.rfc_9728_resource_policy_uri = "https://example.com/privacy"
105
+
106
+ # URL to the resource's terms of service.
107
+ # config.rfc_9728_resource_tos_uri = "https://example.com/tos"
108
+
109
+ # ==========================================================================
110
+ # Scopes
111
+ # ==========================================================================
112
+
113
+ # Configure allowed scopes with human-friendly display names.
114
+ # Keys are the scope strings (used as the allowlist), values are display names
115
+ # shown on the consent screen.
116
+ #
117
+ # Set to nil or {} to disable scope validation entirely.
118
+ # When configured, only these scopes are allowed in authorization requests.
119
+ # config.scopes = {
120
+ # "read" => "Read access to your data",
121
+ # "write" => "Write access to your data"
122
+ # }
123
+
124
+ # Require the scope parameter in authorization requests.
125
+ # When true, clients must specify at least one scope.
126
+ # config.require_scope = false
127
+
128
+ # ==========================================================================
129
+ # Resource Indicators (RFC 8707)
130
+ # ==========================================================================
131
+
132
+ # Configure allowed resources with human-friendly display names.
133
+ # Keys are the resource URIs (used as the allowlist), values are display names
134
+ # shown on the consent screen.
135
+ #
136
+ # Set to nil or {} to disable resource indicators entirely.
137
+ # When configured, only these resources are allowed in authorization requests.
138
+ # config.rfc_8707_resources = {
139
+ # "https://api.example.com/" => "Main API",
140
+ # "https://billing.example.com/" => "Billing Service"
141
+ # }
142
+
143
+ # Require the resource parameter in authorization requests.
144
+ # When true, clients must specify at least one resource.
145
+ # config.rfc_8707_require_resource = false
146
+
147
+ # ==========================================================================
148
+ # Dynamic Client Registration (RFC 7591)
149
+ # ==========================================================================
150
+
151
+ # Enable dynamic client registration endpoint (/register).
152
+ # When enabled, clients can register programmatically via POST requests.
153
+ # Disabled by default for security - enable only if you need this feature.
154
+ # config.rfc_7591_enabled = false
155
+
156
+ # Require an initial access token for client registration.
157
+ # When enabled, registration requests must include a Bearer token.
158
+ # config.rfc_7591_require_initial_access_token = false
159
+
160
+ # Validator proc for initial access tokens.
161
+ # Must return true if the token is valid, false otherwise.
162
+ # Example:
163
+ # config.rfc_7591_initial_access_token_validator = ->(token) {
164
+ # token == ENV["REGISTRATION_ACCESS_TOKEN"]
165
+ # }
166
+
167
+ # Allowed grant types for dynamically registered clients.
168
+ # config.rfc_7591_allowed_grant_types = %w[authorization_code refresh_token]
169
+
170
+ # Allowed response types for dynamically registered clients.
171
+ # config.rfc_7591_allowed_response_types = %w[code]
172
+
173
+ # Allowed token endpoint authentication methods.
174
+ # Options: none, client_secret_basic, client_secret_post, client_secret_jwt, private_key_jwt
175
+ # config.rfc_7591_allowed_token_endpoint_auth_methods = %w[none client_secret_basic client_secret_post client_secret_jwt private_key_jwt]
176
+
177
+ # Client secret expiration duration in seconds (nil = never expires).
178
+ # config.rfc_7591_client_secret_expiration = nil
179
+
180
+ # JWKS for verifying software statements (signed JWTs with client metadata).
181
+ # Set to a JWKS hash to enable software statement verification.
182
+ # config.rfc_7591_software_statement_jwks = nil
183
+
184
+ # Require software statements for client registration.
185
+ # When enabled, registration requests must include a valid software_statement.
186
+ # config.rfc_7591_software_statement_required = false
187
+
188
+ # Cache TTL in seconds for fetched JWKS from jwks_uri (default: 1 hour).
189
+ # config.rfc_7591_jwks_cache_ttl = 3600
190
+
191
+ # ==========================================================================
192
+ # Client Metadata Document (draft-ietf-oauth-client-id-metadata-document)
193
+ # ==========================================================================
194
+
195
+ # URL-based client identifiers allow clients to use HTTPS URLs as their client_id.
196
+ # The authorization server fetches client metadata from the URL at runtime.
197
+ # This enables lightweight, decentralized client registration.
198
+ #
199
+ # SECURITY CONSIDERATION: By default, any HTTPS URL can be used as a client_id,
200
+ # meaning any server on the internet can act as an OAuth client to your
201
+ # authorization server. This is appropriate for MCP servers and open ecosystems.
202
+ # For restricted access, configure allowed_hosts to limit which domains can
203
+ # host client metadata documents.
204
+ #
205
+ # Example for production with restricted access:
206
+ # config.client_metadata_document_allowed_hosts = ["trusted-partner.com", "*.mycompany.com"]
207
+
208
+ # Enable URL-based client identifiers (default: true).
209
+ # config.client_metadata_document_enabled = true
210
+
211
+ # Allowed hosts for client metadata document URLs (default: nil = all hosts).
212
+ # config.client_metadata_document_allowed_hosts = nil
213
+
214
+ # Blocked hosts for client metadata document URLs (default: []).
215
+ # Example: ["internal.example.com", "*.local"]
216
+ # config.client_metadata_document_blocked_hosts = []
217
+
218
+ # Cache TTL in seconds for fetched metadata documents (default: 1 hour).
219
+ # config.client_metadata_document_cache_ttl = 3600
220
+
221
+ # Maximum response size in bytes (default: 5KB).
222
+ # config.client_metadata_document_max_response_size = 5120
223
+
224
+ # Connection and read timeouts in seconds (default: 5 each).
225
+ # config.client_metadata_document_connect_timeout = 5
226
+ # config.client_metadata_document_read_timeout = 5
227
+
228
+ # ==========================================================================
229
+ # Event Logging
230
+ # ==========================================================================
231
+
232
+ # TokenAuthority emits structured events using Rails 8.1's event reporting.
233
+ # Events are automatically logged to Rails.logger when enabled.
234
+ #
235
+ # Events include: authorization requests, consent actions, token exchanges,
236
+ # token refreshes, revocations, client authentication, and security events
237
+ # (e.g., token theft detection).
238
+
239
+ # Enable event logging (default: true).
240
+ # When enabled, events are emitted and logged to Rails.logger.
241
+ # config.event_logging_enabled = true
242
+
243
+ # Enable debug events (default: false).
244
+ # Debug events provide detailed information useful during development,
245
+ # such as PKCE validation steps and cache hits/misses.
246
+ # config.event_logging_debug_events = false
247
+ end
@@ -0,0 +1,397 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TokenAuthority
4
+ # Configuration class for TokenAuthority engine settings.
5
+ #
6
+ # This class manages all configuration options for the OAuth 2.1 provider,
7
+ # including JWT settings, user authentication integration, UI customization,
8
+ # and RFC-specific feature flags.
9
+ #
10
+ # Configuration is typically set in a Rails initializer using a configure block
11
+ # that yields this configuration object.
12
+ #
13
+ # @example Basic configuration
14
+ # TokenAuthority.configure do |config|
15
+ # config.secret_key = Rails.application.credentials.secret_key_base
16
+ # config.user_class = "User"
17
+ # config.rfc_9068_audience_url = "https://api.example.com"
18
+ # config.rfc_9068_issuer_url = "https://example.com"
19
+ # end
20
+ #
21
+ # @example Enabling scopes
22
+ # TokenAuthority.configure do |config|
23
+ # config.scopes = {
24
+ # "read" => "Read access to your data",
25
+ # "write" => "Write access to your data"
26
+ # }
27
+ # config.require_scope = true
28
+ # end
29
+ #
30
+ # @since 0.2.0
31
+ class Configuration
32
+ # @!attribute [rw] secret_key
33
+ # The secret key used for JWT signing and HMAC operations.
34
+ # This should be a secure random string, typically derived from Rails credentials.
35
+ # @return [String] the secret key
36
+ attr_accessor :secret_key
37
+
38
+ # @!attribute [rw] rfc_9068_audience_url
39
+ # The default audience (aud) claim for JWT access tokens per RFC 9068.
40
+ # Identifies the intended recipient of the token (typically the API server).
41
+ # @return [String, nil] the audience URL
42
+ attr_accessor :rfc_9068_audience_url
43
+
44
+ # @!attribute [rw] rfc_9068_issuer_url
45
+ # The issuer (iss) claim for JWT access tokens per RFC 9068.
46
+ # Identifies the authorization server that issued the token.
47
+ # @return [String, nil] the issuer URL
48
+ attr_accessor :rfc_9068_issuer_url
49
+
50
+ # @!attribute [rw] rfc_9068_default_access_token_duration
51
+ # Default lifetime for access tokens in seconds.
52
+ # @return [Integer] duration in seconds (default: 300)
53
+ attr_accessor :rfc_9068_default_access_token_duration
54
+
55
+ # @!attribute [rw] rfc_9068_default_refresh_token_duration
56
+ # Default lifetime for refresh tokens in seconds.
57
+ # @return [Integer] duration in seconds (default: 1,209,600)
58
+ attr_accessor :rfc_9068_default_refresh_token_duration
59
+
60
+ # @!attribute [rw] authenticatable_controller
61
+ # The controller class name that provides authentication methods.
62
+ # Must implement `authenticate_user!` and `current_user` methods.
63
+ # @return [String] controller class name (default: "ApplicationController")
64
+ attr_accessor :authenticatable_controller
65
+
66
+ # @!attribute [rw] user_class
67
+ # The user model class name in the host application.
68
+ # @return [String] user class name (default: "User")
69
+ attr_accessor :user_class
70
+
71
+ # @!attribute [rw] consent_page_layout
72
+ # The layout to use for the OAuth consent screen.
73
+ # @return [String] layout name (default: "application")
74
+ attr_accessor :consent_page_layout
75
+
76
+ # @!attribute [rw] error_page_layout
77
+ # The layout to use for OAuth error pages.
78
+ # @return [String] layout name (default: "application")
79
+ attr_accessor :error_page_layout
80
+
81
+ # @!attribute [rw] rfc_8414_service_documentation
82
+ # URL for service documentation in authorization server metadata per RFC 8414.
83
+ # @return [String, nil] documentation URL
84
+ attr_accessor :rfc_8414_service_documentation
85
+
86
+ # @!attribute [rw] scopes
87
+ # Hash mapping scope strings to human-readable descriptions.
88
+ # Set to nil or empty hash to disable scopes.
89
+ # @example
90
+ # config.scopes = {
91
+ # "read" => "Read access to your data",
92
+ # "write" => "Write access to your data"
93
+ # }
94
+ # @return [Hash{String => String}, nil] scope mappings
95
+ attr_accessor :scopes
96
+
97
+ # @!attribute [rw] require_scope
98
+ # Whether clients must include a scope parameter in authorization requests.
99
+ # @return [Boolean] true if scope is required (default: false)
100
+ attr_accessor :require_scope
101
+
102
+ # @!attribute [rw] rfc_9728_resource
103
+ # The resource URI for protected resource metadata per RFC 9728.
104
+ # @return [String, nil] resource URI
105
+ attr_accessor :rfc_9728_resource
106
+
107
+ # @!attribute [rw] rfc_9728_scopes_supported
108
+ # Array of OAuth scopes supported by the protected resource per RFC 9728.
109
+ # @return [Array<String>, nil] supported scopes
110
+ attr_accessor :rfc_9728_scopes_supported
111
+
112
+ # @!attribute [rw] rfc_9728_authorization_servers
113
+ # Array of authorization server issuer URLs per RFC 9728.
114
+ # @return [Array<String>, nil] authorization server URLs
115
+ attr_accessor :rfc_9728_authorization_servers
116
+
117
+ # @!attribute [rw] rfc_9728_bearer_methods_supported
118
+ # Array of bearer token methods supported per RFC 9728.
119
+ # @return [Array<String>, nil] bearer methods
120
+ attr_accessor :rfc_9728_bearer_methods_supported
121
+
122
+ # @!attribute [rw] rfc_9728_jwks_uri
123
+ # URL to the JWKS for protected resource per RFC 9728.
124
+ # @return [String, nil] JWKS URI
125
+ attr_accessor :rfc_9728_jwks_uri
126
+
127
+ # @!attribute [rw] rfc_9728_resource_name
128
+ # Human-readable name of the protected resource per RFC 9728.
129
+ # @return [String, nil] resource name
130
+ attr_accessor :rfc_9728_resource_name
131
+
132
+ # @!attribute [rw] rfc_9728_resource_documentation
133
+ # URL to documentation for the protected resource per RFC 9728.
134
+ # @return [String, nil] documentation URL
135
+ attr_accessor :rfc_9728_resource_documentation
136
+
137
+ # @!attribute [rw] rfc_9728_resource_policy_uri
138
+ # URL to privacy policy for the protected resource per RFC 9728.
139
+ # @return [String, nil] policy URI
140
+ attr_accessor :rfc_9728_resource_policy_uri
141
+
142
+ # @!attribute [rw] rfc_9728_resource_tos_uri
143
+ # URL to terms of service for the protected resource per RFC 9728.
144
+ # @return [String, nil] TOS URI
145
+ attr_accessor :rfc_9728_resource_tos_uri
146
+
147
+ # @!attribute [rw] rfc_7591_enabled
148
+ # Enable dynamic client registration per RFC 7591.
149
+ # @return [Boolean] true if enabled (default: false)
150
+ attr_accessor :rfc_7591_enabled
151
+
152
+ # @!attribute [rw] rfc_7591_require_initial_access_token
153
+ # Require initial access token for client registration per RFC 7591.
154
+ # @return [Boolean] true if required (default: false)
155
+ attr_accessor :rfc_7591_require_initial_access_token
156
+
157
+ # @!attribute [rw] rfc_7591_initial_access_token_validator
158
+ # Callable object to validate initial access tokens.
159
+ # Should accept a token string and return true/false.
160
+ # @return [Proc, nil] validator callable
161
+ attr_accessor :rfc_7591_initial_access_token_validator
162
+
163
+ # @!attribute [rw] rfc_7591_allowed_grant_types
164
+ # Array of grant types allowed during client registration per RFC 7591.
165
+ # @return [Array<String>] allowed grant types
166
+ attr_accessor :rfc_7591_allowed_grant_types
167
+
168
+ # @!attribute [rw] rfc_7591_allowed_response_types
169
+ # Array of response types allowed during client registration per RFC 7591.
170
+ # @return [Array<String>] allowed response types
171
+ attr_accessor :rfc_7591_allowed_response_types
172
+
173
+ # @!attribute [rw] rfc_7591_allowed_scopes
174
+ # Array of scopes allowed during client registration per RFC 7591.
175
+ # @return [Array<String>, nil] allowed scopes
176
+ attr_accessor :rfc_7591_allowed_scopes
177
+
178
+ # @!attribute [rw] rfc_7591_allowed_token_endpoint_auth_methods
179
+ # Array of token endpoint authentication methods allowed per RFC 7591.
180
+ # @return [Array<String>] allowed auth methods
181
+ attr_accessor :rfc_7591_allowed_token_endpoint_auth_methods
182
+
183
+ # @!attribute [rw] rfc_7591_client_secret_expiration
184
+ # Duration in seconds before client secrets expire, or nil for no expiration.
185
+ # @return [Integer, nil] expiration duration in seconds
186
+ attr_accessor :rfc_7591_client_secret_expiration
187
+
188
+ # @!attribute [rw] rfc_7591_software_statement_jwks
189
+ # JWKS for verifying software statements during registration per RFC 7591.
190
+ # @return [Hash, nil] JWKS
191
+ attr_accessor :rfc_7591_software_statement_jwks
192
+
193
+ # @!attribute [rw] rfc_7591_software_statement_required
194
+ # Require software statements during client registration per RFC 7591.
195
+ # @return [Boolean] true if required (default: false)
196
+ attr_accessor :rfc_7591_software_statement_required
197
+
198
+ # @!attribute [rw] rfc_7591_jwks_cache_ttl
199
+ # Time-to-live for cached JWKS in seconds.
200
+ # @return [Integer] TTL in seconds (default: 3600)
201
+ attr_accessor :rfc_7591_jwks_cache_ttl
202
+
203
+ # @!attribute [rw] client_metadata_document_enabled
204
+ # Enable support for client metadata documents (URL-based client IDs).
205
+ # @return [Boolean] true if enabled (default: true)
206
+ attr_accessor :client_metadata_document_enabled
207
+
208
+ # @!attribute [rw] client_metadata_document_cache_ttl
209
+ # Time-to-live for cached client metadata documents in seconds.
210
+ # @return [Integer] TTL in seconds (default: 3600)
211
+ attr_accessor :client_metadata_document_cache_ttl
212
+
213
+ # @!attribute [rw] client_metadata_document_max_response_size
214
+ # Maximum size in bytes for client metadata document HTTP responses.
215
+ # @return [Integer] max size in bytes (default: 5120)
216
+ attr_accessor :client_metadata_document_max_response_size
217
+
218
+ # @!attribute [rw] client_metadata_document_allowed_hosts
219
+ # Whitelist of hosts allowed for client metadata document URLs.
220
+ # @return [Array<String>, nil] allowed hosts
221
+ attr_accessor :client_metadata_document_allowed_hosts
222
+
223
+ # @!attribute [rw] client_metadata_document_blocked_hosts
224
+ # Blacklist of hosts blocked for client metadata document URLs.
225
+ # @return [Array<String>] blocked hosts (default: [])
226
+ attr_accessor :client_metadata_document_blocked_hosts
227
+
228
+ # @!attribute [rw] client_metadata_document_connect_timeout
229
+ # Connection timeout in seconds for fetching client metadata documents.
230
+ # @return [Integer] timeout in seconds (default: 5)
231
+ attr_accessor :client_metadata_document_connect_timeout
232
+
233
+ # @!attribute [rw] client_metadata_document_read_timeout
234
+ # Read timeout in seconds for fetching client metadata documents.
235
+ # @return [Integer] timeout in seconds (default: 5)
236
+ attr_accessor :client_metadata_document_read_timeout
237
+
238
+ # @!attribute [rw] rfc_8707_resources
239
+ # Hash mapping resource URIs to human-readable descriptions per RFC 8707.
240
+ # Set to nil or empty hash to disable resource indicators.
241
+ # @example
242
+ # config.rfc_8707_resources = {
243
+ # "https://api.example.com" => "Main API",
244
+ # "https://files.example.com" => "File Storage API"
245
+ # }
246
+ # @return [Hash{String => String}, nil] resource mappings
247
+ attr_accessor :rfc_8707_resources
248
+
249
+ # @!attribute [rw] rfc_8707_require_resource
250
+ # Whether clients must include a resource parameter per RFC 8707.
251
+ # @return [Boolean] true if required (default: false)
252
+ attr_accessor :rfc_8707_require_resource
253
+
254
+ # @!attribute [rw] event_logging_enabled
255
+ # Enable structured event logging for OAuth flows and security events.
256
+ # @return [Boolean] true if enabled (default: true)
257
+ attr_accessor :event_logging_enabled
258
+
259
+ # @!attribute [rw] event_logging_debug_events
260
+ # Enable debug-level event logging for troubleshooting.
261
+ # @return [Boolean] true if enabled (default: false)
262
+ attr_accessor :event_logging_debug_events
263
+
264
+ # @!attribute [rw] instrumentation_enabled
265
+ # Enable ActiveSupport::Notifications instrumentation for performance monitoring.
266
+ # @return [Boolean] true if enabled (default: true)
267
+ attr_accessor :instrumentation_enabled
268
+
269
+ def initialize
270
+ # General
271
+ @secret_key = nil
272
+
273
+ # User Authentication
274
+ @authenticatable_controller = "ApplicationController"
275
+ @user_class = "User"
276
+
277
+ # UI/Layout
278
+ @consent_page_layout = "application"
279
+ @error_page_layout = "application"
280
+
281
+ # Scopes
282
+ @scopes = nil
283
+ @require_scope = false
284
+
285
+ # JWT Access Tokens (RFC 9068)
286
+ @rfc_9068_audience_url = nil
287
+ @rfc_9068_issuer_url = nil
288
+ @rfc_9068_default_access_token_duration = 300 # 5 minutes in seconds
289
+ @rfc_9068_default_refresh_token_duration = 1_209_600 # 14 days in seconds
290
+
291
+ # Server Metadata (RFC 8414)
292
+ @rfc_8414_service_documentation = nil
293
+
294
+ # Protected Resource Metadata (RFC 9728)
295
+ @rfc_9728_resource = nil
296
+ @rfc_9728_scopes_supported = nil
297
+ @rfc_9728_authorization_servers = nil
298
+ @rfc_9728_bearer_methods_supported = nil
299
+ @rfc_9728_jwks_uri = nil
300
+ @rfc_9728_resource_name = nil
301
+ @rfc_9728_resource_documentation = nil
302
+ @rfc_9728_resource_policy_uri = nil
303
+ @rfc_9728_resource_tos_uri = nil
304
+
305
+ # Dynamic Client Registration (RFC 7591)
306
+ @rfc_7591_enabled = false
307
+ @rfc_7591_require_initial_access_token = false
308
+ @rfc_7591_initial_access_token_validator = nil
309
+ @rfc_7591_allowed_grant_types = %w[authorization_code refresh_token]
310
+ @rfc_7591_allowed_response_types = %w[code]
311
+ @rfc_7591_allowed_scopes = nil
312
+ @rfc_7591_allowed_token_endpoint_auth_methods = %w[none client_secret_basic client_secret_post client_secret_jwt private_key_jwt]
313
+ @rfc_7591_client_secret_expiration = nil
314
+ @rfc_7591_software_statement_jwks = nil
315
+ @rfc_7591_software_statement_required = false
316
+ @rfc_7591_jwks_cache_ttl = 3600
317
+
318
+ # Client Metadata Document (draft-ietf-oauth-client-id-metadata-document)
319
+ @client_metadata_document_enabled = true
320
+ @client_metadata_document_cache_ttl = 3600
321
+ @client_metadata_document_max_response_size = 5120
322
+ @client_metadata_document_allowed_hosts = nil
323
+ @client_metadata_document_blocked_hosts = []
324
+ @client_metadata_document_connect_timeout = 5
325
+ @client_metadata_document_read_timeout = 5
326
+
327
+ # Resource Indicators (RFC 8707)
328
+ @rfc_8707_resources = nil
329
+ @rfc_8707_require_resource = false
330
+
331
+ # Event Logging
332
+ @event_logging_enabled = true
333
+ @event_logging_debug_events = false
334
+
335
+ # Instrumentation
336
+ @instrumentation_enabled = true
337
+ end
338
+
339
+ # Checks whether the scopes feature is enabled.
340
+ # Scopes are considered enabled when the scopes attribute is a non-empty hash.
341
+ #
342
+ # @return [Boolean] true if scopes are enabled
343
+ def scopes_enabled?
344
+ scopes.is_a?(Hash) && scopes.any?
345
+ end
346
+
347
+ # Checks whether RFC 8707 resource indicators are enabled.
348
+ # Resource indicators are considered enabled when rfc_8707_resources is a non-empty hash.
349
+ #
350
+ # @return [Boolean] true if resource indicators are enabled
351
+ def rfc_8707_enabled?
352
+ rfc_8707_resources.is_a?(Hash) && rfc_8707_resources.any?
353
+ end
354
+
355
+ # Validates the configuration for internal consistency.
356
+ # Ensures that required features are properly configured before use.
357
+ #
358
+ # @raise [ConfigurationError] if require_scope is true but scopes are not configured
359
+ # @raise [ConfigurationError] if rfc_8707_require_resource is true but resources are not configured
360
+ # @return [void]
361
+ def validate!
362
+ if require_scope && !scopes_enabled?
363
+ raise ConfigurationError, "require_scope is true but no scopes are configured"
364
+ end
365
+
366
+ if rfc_8707_require_resource && !rfc_8707_enabled?
367
+ raise ConfigurationError, "rfc_8707_require_resource is true but no rfc_8707_resources are configured"
368
+ end
369
+ end
370
+ end
371
+
372
+ class << self
373
+ # Returns the current configuration instance.
374
+ # Creates a new configuration with default values if one doesn't exist.
375
+ #
376
+ # @return [Configuration] the configuration instance
377
+ def config
378
+ @config ||= Configuration.new
379
+ end
380
+
381
+ # Yields the configuration instance for setup in initializers.
382
+ # This is the primary way to configure TokenAuthority in a Rails application.
383
+ #
384
+ # @example
385
+ # TokenAuthority.configure do |config|
386
+ # config.secret_key = Rails.application.credentials.secret_key_base
387
+ # config.user_class = "User"
388
+ # end
389
+ #
390
+ # @yield [config] configuration block
391
+ # @yieldparam config [Configuration] the configuration instance to modify
392
+ # @return [void]
393
+ def configure
394
+ yield(config)
395
+ end
396
+ end
397
+ end
@@ -1,5 +1,39 @@
1
1
  module TokenAuthority
2
+ # Rails engine that integrates TokenAuthority into host applications.
3
+ #
4
+ # The engine uses an isolated namespace to avoid conflicts with the host application's
5
+ # models and controllers. It sets up initializers for event logging and instrumentation
6
+ # based on the configuration settings.
7
+ #
8
+ # @note This engine is automatically loaded when the TokenAuthority gem is required
9
+ # in a Rails application.
10
+ #
11
+ # @since 0.2.0
2
12
  class Engine < ::Rails::Engine
3
13
  isolate_namespace TokenAuthority
14
+
15
+ # Registers the event subscriber to capture and log OAuth flow events.
16
+ # Only runs if event_logging_enabled is true in the configuration.
17
+ #
18
+ # Events are published through Rails.event and include authorization grants,
19
+ # token exchanges, and security-related activities.
20
+ initializer "token_authority.event_logging", after: :load_config_initializers do
21
+ if TokenAuthority.config.event_logging_enabled
22
+ require "token_authority/log_event_subscriber"
23
+ Rails.event.subscribe(TokenAuthority::LogEventSubscriber.new)
24
+ end
25
+ end
26
+
27
+ # Attaches the instrumentation log subscriber to capture performance metrics.
28
+ # Only runs if instrumentation_enabled is true in the configuration.
29
+ #
30
+ # Instrumentation uses ActiveSupport::Notifications to track timing and
31
+ # performance of key operations like JWT encoding/decoding and session creation.
32
+ initializer "token_authority.instrumentation", after: :load_config_initializers do
33
+ if TokenAuthority.config.instrumentation_enabled
34
+ require "token_authority/instrumentation_log_subscriber"
35
+ TokenAuthority::InstrumentationLogSubscriber.subscribe!
36
+ end
37
+ end
4
38
  end
5
39
  end