aris 1.4.2 → 1.5.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +251 -0
  3. data/README.md +18 -0
  4. data/docs/ADAPTERS.md +478 -0
  5. data/docs/ARCHITECTURE.md +222 -0
  6. data/docs/CONTENT.md +967 -0
  7. data/docs/PERFORMANCE.md +492 -0
  8. data/docs/PLUGIN_DEVELOPMENT.md +688 -0
  9. data/docs/USAGE.md +4998 -0
  10. data/docs/plugins/API_KEY_AUTH.md +232 -0
  11. data/docs/plugins/BASIC_AUTH.md +582 -0
  12. data/docs/plugins/BEARER_AUTH.md +394 -0
  13. data/docs/plugins/CACHE.md +369 -0
  14. data/docs/plugins/COMPRESSION.md +216 -0
  15. data/docs/plugins/COOKIES.md +30 -0
  16. data/docs/plugins/CORS.md +283 -0
  17. data/docs/plugins/CSRF.md +751 -0
  18. data/docs/plugins/ETAG.md +308 -0
  19. data/docs/plugins/FORM_PARSER.md +193 -0
  20. data/docs/plugins/HEALTH_CHECK.md +469 -0
  21. data/docs/plugins/JSON.md +291 -0
  22. data/docs/plugins/MULTIPART.md +427 -0
  23. data/docs/plugins/RATE_LIMITER.md +368 -0
  24. data/docs/plugins/REQUEST_ID.md +369 -0
  25. data/docs/plugins/REQUEST_LOGGER.md +151 -0
  26. data/docs/plugins/SECURITY.md +193 -0
  27. data/docs/plugins/SESSION.md +98 -0
  28. data/lib/aris/adapters/rack/adapter.rb +17 -2
  29. data/lib/aris/adapters/rack/request.rb +29 -11
  30. data/lib/aris/plugins/basic_auth.rb +3 -1
  31. data/lib/aris/plugins/cookies.rb +4 -32
  32. data/lib/aris/plugins/cors.rb +8 -1
  33. data/lib/aris/plugins/csrf.rb +63 -22
  34. data/lib/aris/plugins/flash.rb +3 -1
  35. data/lib/aris/plugins/form_parser.rb +52 -31
  36. data/lib/aris/plugins/multipart.rb +22 -2
  37. data/lib/aris/plugins/request_logger.rb +8 -1
  38. data/lib/aris/plugins/security_headers.rb +8 -1
  39. data/lib/aris/plugins/session.rb +150 -99
  40. data/lib/aris/response_helpers.rb +41 -0
  41. data/lib/aris/version.rb +2 -2
  42. metadata +31 -3
@@ -0,0 +1,232 @@
1
+
2
+ # API Key Auth Plugin
3
+
4
+ Simple API key authentication via custom header.
5
+
6
+ ## Installation
7
+
8
+ ```ruby
9
+ require_relative 'aris/plugins/api_key_auth'
10
+ ```
11
+
12
+ ## Basic Usage
13
+
14
+ ### Single Key
15
+
16
+ ```ruby
17
+ auth = Aris::Plugins::ApiKeyAuth.build(key: ENV['API_KEY'])
18
+
19
+ Aris.routes({
20
+ "api.example.com": {
21
+ use: [auth],
22
+ "/data": { get: { to: DataHandler } }
23
+ }
24
+ })
25
+ ```
26
+
27
+ **Request:**
28
+ ```bash
29
+ curl -H "X-API-Key: your-secret-key" https://api.example.com/data
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Configuration
35
+
36
+ ```ruby
37
+ auth = Aris::Plugins::ApiKeyAuth.build(
38
+ key: 'secret-key', # Single key
39
+ keys: ['key1', 'key2'], # Multiple keys
40
+ validator: ->(k) { valid?(k) }, # Custom validation
41
+ header: 'X-API-Key', # Header name (default)
42
+ realm: 'API' # Realm for WWW-Authenticate
43
+ )
44
+ ```
45
+
46
+ ### Options
47
+
48
+ | Option | Required | Description |
49
+ |:---|:---|:---|
50
+ | `key` | * | Single valid key |
51
+ | `keys` | * | Array of valid keys |
52
+ | `validator` | * | Custom validation `(key) -> Boolean` |
53
+ | `header` | No | Header name (default: `X-API-Key`) |
54
+ | `realm` | No | Realm (default: `API`) |
55
+
56
+ **Note:** Must provide `key`, `keys`, OR `validator`.
57
+
58
+ ---
59
+
60
+ ## Common Patterns
61
+
62
+ ### Multiple Valid Keys
63
+
64
+ ```ruby
65
+ auth = Aris::Plugins::ApiKeyAuth.build(
66
+ keys: [
67
+ ENV['PUBLIC_API_KEY'],
68
+ ENV['PARTNER_API_KEY'],
69
+ ENV['INTERNAL_API_KEY']
70
+ ]
71
+ )
72
+ ```
73
+
74
+ ### Database Validation
75
+
76
+ ```ruby
77
+ auth = Aris::Plugins::ApiKeyAuth.build(
78
+ validator: ->(key) {
79
+ ApiKey.exists?(key: key, active: true)
80
+ }
81
+ )
82
+ ```
83
+
84
+ ### Redis-Cached Validation
85
+
86
+ ```ruby
87
+ auth = Aris::Plugins::ApiKeyAuth.build(
88
+ validator: ->(key) {
89
+ Rails.cache.fetch("api_key:#{key}", expires_in: 5.minutes) do
90
+ ApiKey.valid?(key)
91
+ end
92
+ }
93
+ )
94
+ ```
95
+
96
+ ### Custom Header
97
+
98
+ ```ruby
99
+ auth = Aris::Plugins::ApiKeyAuth.build(
100
+ key: ENV['API_KEY'],
101
+ header: 'X-Custom-API-Key'
102
+ )
103
+ ```
104
+
105
+ **Request:**
106
+ ```bash
107
+ curl -H "X-Custom-API-Key: secret" https://api.example.com/data
108
+ ```
109
+
110
+ ### Per-Domain Keys
111
+
112
+ ```ruby
113
+ public_auth = Aris::Plugins::ApiKeyAuth.build(key: ENV['PUBLIC_KEY'])
114
+ admin_auth = Aris::Plugins::ApiKeyAuth.build(key: ENV['ADMIN_KEY'])
115
+
116
+ Aris.routes({
117
+ "api.example.com": {
118
+ use: [public_auth],
119
+ "/data": { get: { to: DataHandler } }
120
+ },
121
+ "admin-api.example.com": {
122
+ use: [admin_auth],
123
+ "/admin": { get: { to: AdminHandler } }
124
+ }
125
+ })
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Accessing Key in Handler
131
+
132
+ ```ruby
133
+ class DataHandler
134
+ def self.call(request, params)
135
+ api_key = request.instance_variable_get(:@api_key)
136
+
137
+ # Look up associated user/account
138
+ account = Account.find_by(api_key: api_key)
139
+
140
+ { data: account.data }
141
+ end
142
+ end
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Production Tips
148
+
149
+ **1. Use Environment Variables**
150
+
151
+ ```ruby
152
+ auth = Aris::Plugins::ApiKeyAuth.build(
153
+ key: ENV.fetch('API_SECRET_KEY')
154
+ )
155
+ ```
156
+
157
+ **2. Rotate Keys Regularly**
158
+
159
+ ```ruby
160
+ # Support old + new during rotation
161
+ auth = Aris::Plugins::ApiKeyAuth.build(
162
+ keys: [ENV['API_KEY_CURRENT'], ENV['API_KEY_PREVIOUS']]
163
+ )
164
+ ```
165
+
166
+ **3. Rate Limit by Key**
167
+
168
+ ```ruby
169
+ rate_limit = RateLimiter.build(
170
+ key_extractor: ->(request) {
171
+ request.instance_variable_get(:@api_key)
172
+ }
173
+ )
174
+
175
+ Aris.routes({
176
+ "api.example.com": {
177
+ use: [api_key_auth, rate_limit], # Auth first, then rate limit by key
178
+ "/data": { get: { to: DataHandler } }
179
+ }
180
+ })
181
+ ```
182
+
183
+ **4. Log Failed Attempts**
184
+
185
+ ```ruby
186
+ auth = Aris::Plugins::ApiKeyAuth.build(
187
+ validator: ->(key) {
188
+ valid = ApiKey.valid?(key)
189
+ unless valid
190
+ Rails.logger.warn("Invalid API key attempt: #{key[0..8]}...")
191
+ end
192
+ valid
193
+ }
194
+ )
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Error Response
200
+
201
+ **401 Unauthorized:**
202
+ ```json
203
+ {
204
+ "error": "Unauthorized",
205
+ "message": "Invalid API key"
206
+ }
207
+ ```
208
+
209
+ **Headers:**
210
+ ```
211
+ HTTP/1.1 401 Unauthorized
212
+ content-type: application/json
213
+ WWW-Authenticate: ApiKey realm="API"
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Security Notes
219
+
220
+ - ✅ Use HTTPS always (keys sent in plain text)
221
+ - ✅ Store keys hashed in database
222
+ - ✅ Rotate keys regularly
223
+ - ✅ Different keys per client/environment
224
+ - ✅ Combine with rate limiting
225
+ - ❌ Never log full keys
226
+ - ❌ Never commit keys to version control
227
+
228
+ ---
229
+
230
+ ---
231
+
232
+ Need help? Check out the [full plugin development guide](../docs/plugin-development.md).