standard_id 0.51.2 → 0.53.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/CHANGELOG.md +50 -0
- data/README.md +65 -5
- data/lib/generators/standard_id/install/install_generator.rb +4 -1
- data/lib/generators/standard_id/install/templates/standard_id.rb +13 -558
- data/lib/generators/standard_id/install/templates/standard_id_reference.rb +581 -0
- data/lib/standard_id/app_environment.rb +26 -0
- data/lib/standard_id/config/presets.rb +45 -0
- data/lib/standard_id/config/schema.rb +9 -9
- data/lib/standard_id/config_schema.rb +10 -0
- data/lib/standard_id/engine.rb +1 -1
- data/lib/standard_id/passwordless/verification_service.rb +4 -4
- data/lib/standard_id/provider_registry.rb +1 -1
- data/lib/standard_id/testing/request_helpers.rb +99 -0
- data/lib/standard_id/version.rb +1 -1
- data/lib/standard_id.rb +2 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1aa1e111cbaf2abc19d4b43e57a7c276054bf0522418c7303f855659cb3c259f
|
|
4
|
+
data.tar.gz: 583e0568a53fbf9880c11cd0fbf4e17ae2b98d73b52b2db2725ed5dbe4a5dab0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5410924e96b90aca074e3a322cfa7e59fc54c5412e41927157b19f03c723355724295a67cc9ddb3dec70ca38e548c1bf8062431a46859c6ab153c6416f3b9e6
|
|
7
|
+
data.tar.gz: 3216249e86cd957cc0196518374b2b21073ef03f3f134988f97bedc064ecbbbd9e10a7be88a48606ae7502c9b1dcdecbd8fdd606bea9aa81b361269e2cc9cbbc
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.53.0] - 2026-10-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`StandardId::Testing::RequestHelpers#sign_in_as(account, scope: nil)`.** Signs an
|
|
15
|
+
account in for the following requests in a request spec: it creates a real
|
|
16
|
+
`BrowserSession` and writes the encrypted `session_token` cookie a real sign-in
|
|
17
|
+
writes, built with the host's own cookie jar, so no test-only route is added to
|
|
18
|
+
the app. `scope:` also writes `standard_id_scopes` into the Rails session cookie
|
|
19
|
+
(cookie session store only; any other store raises `ArgumentError`, before
|
|
20
|
+
anything is created). Like a real sign-in it always replaces the Rails session
|
|
21
|
+
cookie, so a later `sign_in_as` never inherits an earlier one's scopes or any
|
|
22
|
+
other session data (flash, CSRF token). Replaces per-app controller
|
|
23
|
+
stubs and `/test/set-session` routes.
|
|
24
|
+
- **`RequestHelpers#bearer_headers_for(account, **jwt_options)`:** `build_jwt` plus
|
|
25
|
+
`bearer_auth_header` in one call.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- **"Production" follows `APP_ENVIRONMENT`, failing closed.** The new
|
|
30
|
+
`StandardId::AppEnvironment.production?` decides every production check in the
|
|
31
|
+
gem: the bypass-code guard (when `passwordless.production_env_detector` is
|
|
32
|
+
unset), the provider-misconfiguration `:raise` mode, and the empty
|
|
33
|
+
`allowed_audiences` boot warning. It reads `APP_ENVIRONMENT` when set (only
|
|
34
|
+
`staging`, `preview`, `development` and `test` are non-production; any other
|
|
35
|
+
value is production), else `Rails.env.production?`. A staging box with
|
|
36
|
+
`RAILS_ENV=production` and `APP_ENVIRONMENT=staging` is therefore no longer
|
|
37
|
+
treated as production, and `-> { AppEnv.production? }` detectors can be
|
|
38
|
+
deleted. Same convention as standard_audit, standard_health and
|
|
39
|
+
standard_singpass.
|
|
40
|
+
- **`rails g standard_id:install` writes a minimal initializer.** It holds only
|
|
41
|
+
`account_class_name`, plus commented `issuer` and `c.preset :inertia_web` lines,
|
|
42
|
+
instead of several hundred lines of commented defaults that apps then kept
|
|
43
|
+
verbatim. `--with-reference` writes
|
|
44
|
+
the annotated initializer as before. Existing initializers are not touched.
|
|
45
|
+
|
|
46
|
+
## [0.52.0] - 2026-10-22
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- **`c.preset :inertia_web`.** Applies the settings an Inertia app with
|
|
51
|
+
passwordless or social sign-in flips: `use_inertia` and `alias_current_user`
|
|
52
|
+
true; `web.signup`, `web.password_login` and `web.password_reset` false;
|
|
53
|
+
`oauth.discovery_endpoint_base = :request`. Each setting is hand-set in four
|
|
54
|
+
of the five estate apps, though the full bundle matches only two of them. A
|
|
55
|
+
preset fills only settings the host has not assigned (via
|
|
56
|
+
`Scope#assigned?`), so explicit assignments win in either order; an unknown
|
|
57
|
+
name raises `ArgumentError`. The public defaults are unchanged.
|
|
58
|
+
Presets live in `StandardId::Config::Presets`.
|
|
59
|
+
|
|
10
60
|
## [0.51.2] - 2026-10-21
|
|
11
61
|
|
|
12
62
|
### Fixed
|
data/README.md
CHANGED
|
@@ -63,6 +63,13 @@ $ bundle install
|
|
|
63
63
|
rails generate standard_id:install
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
This writes a short `config/initializers/standard_id.rb` holding only what an
|
|
67
|
+
app must decide (`account_class_name`, plus commented `issuer` and
|
|
68
|
+
`c.preset :inertia_web` lines). Add a setting only when you change it from the
|
|
69
|
+
default. `--with-reference` writes the annotated initializer instead, with every
|
|
70
|
+
commonly changed setting and its default commented out; it is a reference to
|
|
71
|
+
read, not a file to keep whole.
|
|
72
|
+
|
|
66
73
|
### 2. Configure Your Account Model
|
|
67
74
|
|
|
68
75
|
```ruby
|
|
@@ -629,6 +636,23 @@ StandardId.configure do |config|
|
|
|
629
636
|
end
|
|
630
637
|
```
|
|
631
638
|
|
|
639
|
+
Or start from the `:inertia_web` preset, which bundles the settings an
|
|
640
|
+
Inertia app with passwordless or social sign-in usually flips:
|
|
641
|
+
|
|
642
|
+
```ruby
|
|
643
|
+
StandardId.configure do |config|
|
|
644
|
+
config.preset :inertia_web
|
|
645
|
+
# use_inertia = true, alias_current_user = true,
|
|
646
|
+
# web.signup / web.password_login / web.password_reset = false,
|
|
647
|
+
# oauth.discovery_endpoint_base = :request
|
|
648
|
+
config.web.passwordless_login = true # not part of the preset: your call
|
|
649
|
+
end
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
A preset fills only the settings you haven't assigned, so an explicit
|
|
653
|
+
assignment wins whether it comes before or after `preset`. An unknown name
|
|
654
|
+
raises `ArgumentError`. The public defaults are unchanged.
|
|
655
|
+
|
|
632
656
|
3. Create the corresponding frontend components. The component path follows the pattern:
|
|
633
657
|
`{namespace}/{ControllerName}/{action}`
|
|
634
658
|
|
|
@@ -852,15 +876,19 @@ end
|
|
|
852
876
|
|
|
853
877
|
**Bypass code (E2E testing).** When `StandardId.config.passwordless.bypass_code` is set (and the deploy is not production), `Otp.verify` accepts the bypass code for **any realm**. This replaces per-app bypass ENV checks and works consistently across `Otp.verify` and the built-in passwordless login flow. Never set `bypass_code` in production — it will raise if you try.
|
|
854
878
|
|
|
855
|
-
|
|
879
|
+
"Production" is decided by `StandardId::AppEnvironment`, the same rule every
|
|
880
|
+
check in the gem uses: `APP_ENVIRONMENT` when it is set, where only `staging`,
|
|
881
|
+
`preview`, `development` and `test` count as non-production (any other value,
|
|
882
|
+
including a typo, is production), else `Rails.env.production?`. So a staging box
|
|
883
|
+
running `RAILS_ENV=production` with `APP_ENVIRONMENT=staging` is not
|
|
884
|
+
production, and needs no extra wiring:
|
|
856
885
|
|
|
857
886
|
```ruby
|
|
858
|
-
|
|
859
|
-
c.passwordless.production_env_detector = -> { AppEnv.production? }
|
|
860
|
-
c.passwordless.bypass_code = ENV["STANDARD_ID_BYPASS_CODE"] unless AppEnv.production?
|
|
887
|
+
c.passwordless.bypass_code = ENV["STANDARD_ID_BYPASS_CODE"] unless StandardId::AppEnvironment.production?
|
|
861
888
|
```
|
|
862
889
|
|
|
863
|
-
`production_env_detector`
|
|
890
|
+
`production_env_detector` (a callable taking no arguments, returning a boolean)
|
|
891
|
+
still overrides that, for an app with a different discriminator.
|
|
864
892
|
|
|
865
893
|
**Back-compat.** The existing passwordless authentication flow continues to work unchanged. `Otp.issue`/`Otp.verify` are a new addition — you can migrate direct `CodeChallenge.create!` calls at your own pace.
|
|
866
894
|
|
|
@@ -1926,6 +1954,38 @@ Notes:
|
|
|
1926
1954
|
|
|
1927
1955
|
## Testing
|
|
1928
1956
|
|
|
1957
|
+
### Signing in from your app's request specs
|
|
1958
|
+
|
|
1959
|
+
```ruby
|
|
1960
|
+
# spec/rails_helper.rb
|
|
1961
|
+
require "standard_id/testing"
|
|
1962
|
+
|
|
1963
|
+
RSpec.configure do |config|
|
|
1964
|
+
config.include StandardId::Testing::RequestHelpers, type: :request
|
|
1965
|
+
end
|
|
1966
|
+
```
|
|
1967
|
+
|
|
1968
|
+
```ruby
|
|
1969
|
+
sign_in_as(account) # a real BrowserSession, via the session_token cookie
|
|
1970
|
+
sign_in_as(account, scope: :platform) # also grants standard_id_scopes (current_scope_names)
|
|
1971
|
+
get "/dashboard"
|
|
1972
|
+
|
|
1973
|
+
get "/api/orders", headers: bearer_headers_for(account, scope: "orders.read")
|
|
1974
|
+
```
|
|
1975
|
+
|
|
1976
|
+
`sign_in_as` creates a real `BrowserSession` and writes the same encrypted
|
|
1977
|
+
`session_token` cookie a real sign-in writes, so `current_account`,
|
|
1978
|
+
`require_browser_session!`, expiry and revocation behave exactly as in
|
|
1979
|
+
production. It adds nothing to your app: the cookies are built with your app's
|
|
1980
|
+
own encrypted cookie jar, so there is no test-only route. `scope:` writes the
|
|
1981
|
+
Rails session cookie and so needs the cookie session store (the Rails default);
|
|
1982
|
+
with another store it raises `ArgumentError`, and you sign in through your own
|
|
1983
|
+
scoped login request instead. It replaces controller stubbing
|
|
1984
|
+
(`stub_web_authentication`, `allow_any_instance_of(...).to receive(:current_user)`)
|
|
1985
|
+
and per-app `/test/set-session` routes.
|
|
1986
|
+
|
|
1987
|
+
### This gem's own suite
|
|
1988
|
+
|
|
1929
1989
|
StandardId includes comprehensive test coverage:
|
|
1930
1990
|
|
|
1931
1991
|
```bash
|
|
@@ -28,6 +28,8 @@ module StandardId
|
|
|
28
28
|
|
|
29
29
|
class_option :skip_initializer, type: :boolean, default: false,
|
|
30
30
|
desc: "Do not write config/initializers/standard_id.rb"
|
|
31
|
+
class_option :with_reference, type: :boolean, default: false,
|
|
32
|
+
desc: "Write the annotated initializer (every common setting with its default) instead of the minimal one"
|
|
31
33
|
class_option :skip_routes, type: :boolean, default: false,
|
|
32
34
|
desc: "Do not append engine mount lines to config/routes.rb"
|
|
33
35
|
class_option :skip_migrations, type: :boolean, default: false,
|
|
@@ -51,7 +53,8 @@ module StandardId
|
|
|
51
53
|
def create_initializer_file
|
|
52
54
|
return say_status("skip", "config/initializers/standard_id.rb (--skip-initializer)", :yellow) if options[:skip_initializer]
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
source = options[:with_reference] ? "standard_id_reference.rb" : "standard_id.rb"
|
|
57
|
+
template source, "config/initializers/standard_id.rb"
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
def mount_engines
|