standard_id 0.1.5 → 0.1.6
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/README.md +163 -0
- data/app/controllers/concerns/standard_id/inertia_rendering.rb +49 -0
- data/app/controllers/concerns/standard_id/inertia_support.rb +31 -0
- data/app/controllers/concerns/standard_id/web_authentication.rb +21 -0
- data/app/controllers/standard_id/web/login_controller.rb +6 -2
- data/app/controllers/standard_id/web/signup_controller.rb +8 -2
- data/lib/generators/standard_id/install/templates/standard_id.rb +8 -0
- data/lib/standard_config/config.rb +10 -0
- data/lib/standard_id/config/schema.rb +2 -0
- data/lib/standard_id/version.rb +1 -1
- 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: 7a8069c98c5ede27fc1f485806e5a9b150d4f43294d177f59fe89008e11bd289
|
|
4
|
+
data.tar.gz: e88dae408bce4db81c42c780985d9e4a833b4864636a2d10b5ff979407dc9562
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19f08dcd3da104952f2313669bc7bceb18ef0ce866ff234a0beb966e64d83294cefc76886c2f5e74080b935271444afeae0057deadcbac7bcfda40f6dd0441b4
|
|
7
|
+
data.tar.gz: 2531fba6a76ea0dd4800cebe0444a86cdea8ab516c64888b40b7d60aa681a957af2f3f4fb9622aebc6cf6f25b44a3caf0b3d03f16dcc673ce2f0a30c79599211
|
data/README.md
CHANGED
|
@@ -37,6 +37,11 @@ A comprehensive authentication engine for Rails applications, built on the secur
|
|
|
37
37
|
- **Remember Me**: Extended session support
|
|
38
38
|
- **Account Lockout**: Protection against brute force attacks
|
|
39
39
|
|
|
40
|
+
### ⚡ Frontend Framework Support
|
|
41
|
+
- **Inertia.js Integration**: Optional support for React, Vue, or Svelte frontends
|
|
42
|
+
- **Conditional Rendering**: Automatically switches between ERB and Inertia based on configuration
|
|
43
|
+
- **External Redirects**: Proper handling of OAuth redirects in SPA contexts
|
|
44
|
+
|
|
40
45
|
## Installation
|
|
41
46
|
|
|
42
47
|
Add this line to your application's Gemfile:
|
|
@@ -114,6 +119,10 @@ StandardId.configure do |config|
|
|
|
114
119
|
# Custom layout for web views
|
|
115
120
|
config.web_layout = "application"
|
|
116
121
|
|
|
122
|
+
# Inertia.js support (see Inertia.js Integration section below)
|
|
123
|
+
# config.use_inertia = true
|
|
124
|
+
# config.inertia_component_namespace = "auth"
|
|
125
|
+
|
|
117
126
|
# Passwordless delivery callbacks
|
|
118
127
|
# config.passwordless_email_sender = ->(email, code) { UserMailer.send_code(email, code).deliver_now }
|
|
119
128
|
# config.passwordless_sms_sender = ->(phone, code) { SmsService.send_code(phone, code) }
|
|
@@ -192,6 +201,160 @@ end
|
|
|
192
201
|
|
|
193
202
|
`social_info` is an indifferent-access hash containing at least `email`, `name`, and `provider_id`.
|
|
194
203
|
|
|
204
|
+
### Inertia.js Integration
|
|
205
|
+
|
|
206
|
+
StandardId supports [Inertia.js](https://inertiajs.com/) for modern React, Vue, or Svelte frontends. When enabled, web controllers render Inertia components instead of ERB views.
|
|
207
|
+
|
|
208
|
+
#### Setup
|
|
209
|
+
|
|
210
|
+
1. Add the `inertia_rails` gem to your Gemfile:
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
gem "inertia_rails"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
2. Enable Inertia in your StandardId configuration:
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
StandardId.configure do |config|
|
|
220
|
+
config.use_inertia = true
|
|
221
|
+
config.inertia_component_namespace = "auth" # Optional, defaults to "standard_id"
|
|
222
|
+
end
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
3. Create the corresponding frontend components. The component path follows the pattern:
|
|
226
|
+
`{namespace}/{ControllerName}/{action}`
|
|
227
|
+
|
|
228
|
+
For example, with `inertia_component_namespace = "auth"`:
|
|
229
|
+
- Login page: `pages/auth/login/show.tsx`
|
|
230
|
+
- Signup page: `pages/auth/signup/show.tsx`
|
|
231
|
+
|
|
232
|
+
#### Example Component (React)
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
// frontend/pages/auth/login/show.tsx
|
|
236
|
+
import { useForm } from '@inertiajs/react'
|
|
237
|
+
|
|
238
|
+
interface Props {
|
|
239
|
+
redirect_uri: string
|
|
240
|
+
connection: string | null
|
|
241
|
+
flash: { notice?: string; alert?: string }
|
|
242
|
+
social_providers: { google_enabled: boolean; apple_enabled: boolean }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export default function LoginShow({ redirect_uri, flash, social_providers }: Props) {
|
|
246
|
+
const { data, setData, post, processing } = useForm({
|
|
247
|
+
'login[email]': '',
|
|
248
|
+
'login[password]': '',
|
|
249
|
+
'login[remember_me]': false,
|
|
250
|
+
redirect_uri,
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
const handleSubmit = (e: React.FormEvent) => {
|
|
254
|
+
e.preventDefault()
|
|
255
|
+
post('/login')
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const handleSocialLogin = (connection: string) => {
|
|
259
|
+
post('/login', { data: { connection, redirect_uri } })
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<div className="login-container">
|
|
264
|
+
{flash.alert && <div className="alert alert-error">{flash.alert}</div>}
|
|
265
|
+
{flash.notice && <div className="alert alert-success">{flash.notice}</div>}
|
|
266
|
+
|
|
267
|
+
<form onSubmit={handleSubmit}>
|
|
268
|
+
<div>
|
|
269
|
+
<label htmlFor="email">Email</label>
|
|
270
|
+
<input
|
|
271
|
+
id="email"
|
|
272
|
+
type="email"
|
|
273
|
+
value={data['login[email]']}
|
|
274
|
+
onChange={e => setData('login[email]', e.target.value)}
|
|
275
|
+
required
|
|
276
|
+
/>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<div>
|
|
280
|
+
<label htmlFor="password">Password</label>
|
|
281
|
+
<input
|
|
282
|
+
id="password"
|
|
283
|
+
type="password"
|
|
284
|
+
value={data['login[password]']}
|
|
285
|
+
onChange={e => setData('login[password]', e.target.value)}
|
|
286
|
+
required
|
|
287
|
+
/>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div>
|
|
291
|
+
<label>
|
|
292
|
+
<input
|
|
293
|
+
type="checkbox"
|
|
294
|
+
checked={data['login[remember_me]'] as boolean}
|
|
295
|
+
onChange={e => setData('login[remember_me]', e.target.checked)}
|
|
296
|
+
/>
|
|
297
|
+
Remember me
|
|
298
|
+
</label>
|
|
299
|
+
</div>
|
|
300
|
+
|
|
301
|
+
<button type="submit" disabled={processing}>
|
|
302
|
+
{processing ? 'Signing in...' : 'Sign In'}
|
|
303
|
+
</button>
|
|
304
|
+
</form>
|
|
305
|
+
|
|
306
|
+
{(social_providers.google_enabled || social_providers.apple_enabled) && (
|
|
307
|
+
<div className="social-login">
|
|
308
|
+
<p>Or continue with</p>
|
|
309
|
+
{social_providers.google_enabled && (
|
|
310
|
+
<button type="button" onClick={() => handleSocialLogin('google')}>
|
|
311
|
+
Sign in with Google
|
|
312
|
+
</button>
|
|
313
|
+
)}
|
|
314
|
+
{social_providers.apple_enabled && (
|
|
315
|
+
<button type="button" onClick={() => handleSocialLogin('apple')}>
|
|
316
|
+
Sign in with Apple
|
|
317
|
+
</button>
|
|
318
|
+
)}
|
|
319
|
+
</div>
|
|
320
|
+
)}
|
|
321
|
+
</div>
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
> **Note:** The `useForm` hook from `@inertiajs/react` automatically handles CSRF tokens. When you call `post()`, `put()`, `patch()`, or `delete()`, Inertia reads the CSRF token from the `<meta name="csrf-token">` tag in your layout and includes it in the request headers.
|
|
327
|
+
|
|
328
|
+
#### Props Passed to Components
|
|
329
|
+
|
|
330
|
+
Authentication pages receive the following props:
|
|
331
|
+
|
|
332
|
+
| Prop | Type | Description |
|
|
333
|
+
|------|------|-------------|
|
|
334
|
+
| `redirect_uri` | `string` | URL to redirect to after authentication |
|
|
335
|
+
| `connection` | `string \| null` | Social provider connection (if any) |
|
|
336
|
+
| `flash` | `{ notice?: string, alert?: string }` | Flash messages |
|
|
337
|
+
| `social_providers` | `{ google_enabled: boolean, apple_enabled: boolean }` | Available social providers |
|
|
338
|
+
| `errors` | `object` | Validation errors (on form submission failures) |
|
|
339
|
+
|
|
340
|
+
#### Using Authentication in Host App Controllers
|
|
341
|
+
|
|
342
|
+
You can use the `authenticate_account!` method in your own controllers to require authentication with Inertia-compatible redirects:
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
class DashboardController < ApplicationController
|
|
346
|
+
include StandardId::WebAuthentication
|
|
347
|
+
|
|
348
|
+
before_action :authenticate_account!
|
|
349
|
+
|
|
350
|
+
def show
|
|
351
|
+
# Only authenticated users can access this
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
This will redirect unauthenticated users to the login page using `inertia_location` for Inertia requests, ensuring proper SPA navigation.
|
|
357
|
+
|
|
195
358
|
### Passwordless Authentication
|
|
196
359
|
|
|
197
360
|
```ruby
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module StandardId
|
|
2
|
+
module InertiaRendering
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
include StandardId::InertiaSupport
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Render with Inertia if enabled, otherwise use standard Rails rendering
|
|
12
|
+
def render_with_inertia(action: nil, props: {}, component: nil, status: :ok, **options)
|
|
13
|
+
if use_inertia?
|
|
14
|
+
component_name = component || inertia_component_name(action)
|
|
15
|
+
render inertia: component_name, props: props, status: status, **options
|
|
16
|
+
else
|
|
17
|
+
render_options = { status: status }
|
|
18
|
+
render_options[:action] = action if action.present?
|
|
19
|
+
render_options.merge!(options.except(:inertia, :props))
|
|
20
|
+
render(**render_options)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Generate the Inertia component name based on controller and action
|
|
25
|
+
def inertia_component_name(action = nil)
|
|
26
|
+
namespace = StandardId.config.inertia_component_namespace.presence || "standard_id"
|
|
27
|
+
controller_name = self.class.name.demodulize.delete_suffix("Controller")
|
|
28
|
+
action_str = (action || self.action_name).to_s
|
|
29
|
+
|
|
30
|
+
"#{namespace}/#{controller_name}/#{action_str}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Build common props for authentication pages
|
|
34
|
+
def auth_page_props(additional_props = {})
|
|
35
|
+
{
|
|
36
|
+
redirect_uri: @redirect_uri,
|
|
37
|
+
connection: @connection,
|
|
38
|
+
flash: {
|
|
39
|
+
notice: flash[:notice],
|
|
40
|
+
alert: flash[:alert]
|
|
41
|
+
}.compact,
|
|
42
|
+
social_providers: {
|
|
43
|
+
google_enabled: StandardId.config.google_client_id.present?,
|
|
44
|
+
apple_enabled: StandardId.config.apple_client_id.present?
|
|
45
|
+
}
|
|
46
|
+
}.deep_merge(additional_props)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module StandardId
|
|
2
|
+
module InertiaSupport
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
helper_method :use_inertia?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Check if Inertia rendering should be used
|
|
12
|
+
def use_inertia?
|
|
13
|
+
StandardId.config.use_inertia && inertia_available?
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Check if inertia_rails gem is available in the host application
|
|
17
|
+
def inertia_available?
|
|
18
|
+
defined?(::InertiaRails)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Redirect to an external URL or non-Inertia endpoint
|
|
22
|
+
# Uses inertia_location for Inertia requests, otherwise standard redirect_to
|
|
23
|
+
def redirect_with_inertia(url, **options)
|
|
24
|
+
if use_inertia? && request.inertia?
|
|
25
|
+
inertia_location url
|
|
26
|
+
else
|
|
27
|
+
redirect_to url, **options
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -3,6 +3,7 @@ module StandardId
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
included do
|
|
6
|
+
include StandardId::InertiaSupport
|
|
6
7
|
helper_method :current_account, :authenticated?
|
|
7
8
|
end
|
|
8
9
|
|
|
@@ -18,6 +19,26 @@ module StandardId
|
|
|
18
19
|
authentication_guard.require_session!(session_manager, session: session, request: request)
|
|
19
20
|
end
|
|
20
21
|
|
|
22
|
+
# Require authentication with redirect to login page instead of raising an error.
|
|
23
|
+
# Use this for pages that should redirect unauthenticated users to login.
|
|
24
|
+
def authenticate_account!
|
|
25
|
+
return if authenticated?
|
|
26
|
+
|
|
27
|
+
store_location_for_redirect
|
|
28
|
+
redirect_to_login
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Store the current URL to redirect back after authentication
|
|
32
|
+
def store_location_for_redirect
|
|
33
|
+
session[:return_to_after_authenticating] = request.url if request.get?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Redirect to login page, handling both Inertia and standard requests
|
|
37
|
+
def redirect_to_login
|
|
38
|
+
login_path = StandardId.config.login_url.presence || "/login"
|
|
39
|
+
redirect_with_inertia login_path
|
|
40
|
+
end
|
|
41
|
+
|
|
21
42
|
def after_authentication_url
|
|
22
43
|
# TODO: add configurable value
|
|
23
44
|
session.delete(:return_to_after_authenticating) || "/"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module StandardId
|
|
2
2
|
module Web
|
|
3
3
|
class LoginController < BaseController
|
|
4
|
+
include StandardId::InertiaRendering
|
|
5
|
+
|
|
4
6
|
layout "public"
|
|
5
7
|
|
|
6
8
|
skip_before_action :require_browser_session!, only: [:show, :create]
|
|
@@ -11,6 +13,8 @@ module StandardId
|
|
|
11
13
|
def show
|
|
12
14
|
@redirect_uri = params[:redirect_uri] || after_authentication_url
|
|
13
15
|
@connection = params[:connection]
|
|
16
|
+
|
|
17
|
+
render_with_inertia props: auth_page_props
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def create
|
|
@@ -18,7 +22,7 @@ module StandardId
|
|
|
18
22
|
redirect_to params[:redirect_uri] || after_authentication_url, status: :see_other, notice: "Successfully signed in"
|
|
19
23
|
else
|
|
20
24
|
flash.now[:alert] = "Invalid email or password"
|
|
21
|
-
|
|
25
|
+
render_with_inertia action: :show, props: auth_page_props, status: :unprocessable_content
|
|
22
26
|
end
|
|
23
27
|
end
|
|
24
28
|
|
|
@@ -29,7 +33,7 @@ module StandardId
|
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
def redirect_if_social_login
|
|
32
|
-
|
|
36
|
+
redirect_with_inertia social_login_url, allow_other_host: true if params[:connection].present?
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
def social_login_url
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module StandardId
|
|
2
2
|
module Web
|
|
3
3
|
class SignupController < BaseController
|
|
4
|
+
include StandardId::InertiaRendering
|
|
5
|
+
|
|
4
6
|
layout "public"
|
|
5
7
|
|
|
6
8
|
skip_before_action :require_browser_session!, only: [:show, :create]
|
|
@@ -11,6 +13,8 @@ module StandardId
|
|
|
11
13
|
def show
|
|
12
14
|
@redirect_uri = params[:redirect_uri] || after_authentication_url
|
|
13
15
|
@connection = params[:connection] # For social login detection
|
|
16
|
+
|
|
17
|
+
render_with_inertia props: auth_page_props
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def create
|
|
@@ -24,7 +28,7 @@ module StandardId
|
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
def redirect_if_social_login
|
|
27
|
-
|
|
31
|
+
redirect_with_inertia social_signup_url, allow_other_host: true if params[:connection].present?
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def handle_password_signup
|
|
@@ -35,8 +39,10 @@ module StandardId
|
|
|
35
39
|
redirect_to params[:redirect_uri] || after_authentication_url,
|
|
36
40
|
notice: "Account created successfully"
|
|
37
41
|
else
|
|
42
|
+
@redirect_uri = params[:redirect_uri] || after_authentication_url
|
|
43
|
+
@connection = params[:connection]
|
|
38
44
|
flash.now[:alert] = form.errors.full_messages.join(", ")
|
|
39
|
-
|
|
45
|
+
render_with_inertia action: :show, props: auth_page_props(errors: form.errors.to_hash), status: :unprocessable_content
|
|
40
46
|
end
|
|
41
47
|
end
|
|
42
48
|
|
|
@@ -7,6 +7,14 @@ StandardId.configure do |c|
|
|
|
7
7
|
# c.cache_store = Rails.cache
|
|
8
8
|
# c.logger = Rails.logger
|
|
9
9
|
# c.web_layout = "application"
|
|
10
|
+
|
|
11
|
+
# Inertia.js support (requires inertia_rails gem)
|
|
12
|
+
# When enabled, StandardId web controllers will render Inertia components
|
|
13
|
+
# instead of ERB views. You must create the corresponding components in your
|
|
14
|
+
# frontend (e.g., pages/auth/login/show.tsx)
|
|
15
|
+
# c.use_inertia = true
|
|
16
|
+
# c.inertia_component_namespace = "auth" # Component path prefix (e.g., "auth/login/show")
|
|
17
|
+
|
|
10
18
|
# c.passwordless_email_sender = ->(email, code) { PasswordlessMailer.with(code: code, to: email).deliver_later }
|
|
11
19
|
# c.passwordless_sms_sender = ->(phone, code) { SmsProvider.send_code(phone: phone, code: code) }
|
|
12
20
|
|
|
@@ -42,6 +42,14 @@ module StandardConfig
|
|
|
42
42
|
# Examples: "application", "standard_id/web/application", "my_custom_layout"
|
|
43
43
|
attr_accessor :web_layout
|
|
44
44
|
|
|
45
|
+
# Enable Inertia.js rendering for StandardId Web controllers
|
|
46
|
+
# When true and inertia_rails gem is available, controllers will render Inertia components
|
|
47
|
+
attr_accessor :use_inertia
|
|
48
|
+
|
|
49
|
+
# Namespace prefix for Inertia component paths
|
|
50
|
+
# Example: "Auth" will generate component paths like "Auth/Login/show"
|
|
51
|
+
attr_accessor :inertia_component_namespace
|
|
52
|
+
|
|
45
53
|
def initialize
|
|
46
54
|
@account_class_name = nil
|
|
47
55
|
@cache_store = nil
|
|
@@ -61,6 +69,8 @@ module StandardConfig
|
|
|
61
69
|
@passwordless_sms_sender = nil
|
|
62
70
|
@allowed_post_logout_redirect_uris = []
|
|
63
71
|
@web_layout = nil
|
|
72
|
+
@use_inertia = nil
|
|
73
|
+
@inertia_component_namespace = nil
|
|
64
74
|
end
|
|
65
75
|
|
|
66
76
|
def account_class
|
|
@@ -14,6 +14,8 @@ StandardConfig.schema.draw do
|
|
|
14
14
|
field :issuer, type: :string, default: nil
|
|
15
15
|
field :login_url, type: :string, default: nil
|
|
16
16
|
field :allowed_post_logout_redirect_uris, type: :array, default: []
|
|
17
|
+
field :use_inertia, type: :boolean, default: false
|
|
18
|
+
field :inertia_component_namespace, type: :string, default: "standard_id"
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
scope :passwordless do
|
data/lib/standard_id/version.rb
CHANGED
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.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jaryl Sim
|
|
@@ -65,6 +65,8 @@ files:
|
|
|
65
65
|
- Rakefile
|
|
66
66
|
- app/assets/stylesheets/standard_id/application.css
|
|
67
67
|
- app/controllers/concerns/standard_id/api_authentication.rb
|
|
68
|
+
- app/controllers/concerns/standard_id/inertia_rendering.rb
|
|
69
|
+
- app/controllers/concerns/standard_id/inertia_support.rb
|
|
68
70
|
- app/controllers/concerns/standard_id/social_authentication.rb
|
|
69
71
|
- app/controllers/concerns/standard_id/web_authentication.rb
|
|
70
72
|
- app/controllers/standard_id/api/authorization_controller.rb
|