rodauth-oauth 1.0.0.pre.beta1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/MIGRATION-GUIDE-v1.md +12 -0
  4. data/README.md +30 -15
  5. data/doc/release_notes/0_1_0.md +2 -2
  6. data/doc/release_notes/0_2_0.md +1 -1
  7. data/doc/release_notes/0_3_0.md +1 -1
  8. data/doc/release_notes/0_5_0.md +2 -2
  9. data/doc/release_notes/0_8_0.md +2 -2
  10. data/doc/release_notes/1_0_0.md +79 -0
  11. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +19 -7
  12. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize_error.erb +10 -0
  13. data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +54 -43
  14. data/lib/rodauth/features/oauth_application_management.rb +2 -2
  15. data/lib/rodauth/features/oauth_authorization_code_grant.rb +31 -7
  16. data/lib/rodauth/features/oauth_authorize_base.rb +32 -10
  17. data/lib/rodauth/features/oauth_base.rb +36 -16
  18. data/lib/rodauth/features/oauth_dynamic_client_registration.rb +7 -4
  19. data/lib/rodauth/features/oauth_implicit_grant.rb +16 -5
  20. data/lib/rodauth/features/oauth_jwt.rb +3 -3
  21. data/lib/rodauth/features/oauth_jwt_base.rb +29 -6
  22. data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +7 -4
  23. data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +64 -10
  24. data/lib/rodauth/features/oauth_resource_indicators.rb +0 -4
  25. data/lib/rodauth/features/oauth_resource_server.rb +3 -3
  26. data/lib/rodauth/features/oauth_saml_bearer_grant.rb +2 -0
  27. data/lib/rodauth/features/oidc.rb +263 -187
  28. data/lib/rodauth/features/oidc_dynamic_client_registration.rb +65 -25
  29. data/lib/rodauth/features/oidc_rp_initiated_logout.rb +118 -0
  30. data/lib/rodauth/oauth/http_extensions.rb +15 -2
  31. data/lib/rodauth/oauth/ttl_store.rb +2 -0
  32. data/lib/rodauth/oauth/version.rb +1 -1
  33. data/locales/en.yml +4 -1
  34. data/locales/pt.yml +4 -1
  35. data/templates/authorize.str +17 -10
  36. data/templates/authorize_error.str +12 -0
  37. metadata +15 -12
  38. data/doc/release_notes/1_0_0_beta1.md +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 299307b4879c519f6bcf7e5cfb875b75ac1d6b73b90371d3c9925baaf50dee08
4
- data.tar.gz: 05a87d3e473b514f7cbb67d841a4a9185154dd1d15933d3321a3e4946c9c28ed
3
+ metadata.gz: 8288f66a0f7dd5400b60d2508a0247aefd37f1aa73322c19bf3b744d3e8b1ace
4
+ data.tar.gz: 6f2c333c4c2c3a4f92544f939ac1112d31c78a56779f22234bb7e7ce95105931
5
5
  SHA512:
6
- metadata.gz: 2600d4236957c98ece6db0b06d280675d0e64c203a42e59e52063fea851bb42ec782063da5e8598211ae2a20faf9282616ffba14de8333f4e3a49ba04c97d154
7
- data.tar.gz: 7a3b5a0b1f9979c92329848d57c6de9a68f372f2357d4ade96538aea884124235efeeb3bd28d2336d3dad92344ce59cb61958c868ffa8b12f4771d17b2e1f0f7
6
+ metadata.gz: 612b2651b4c29f98427a5113b403ce214d3d8513cd740977a834f5efdbb4aac46fc83f74f54a2b925836e6860cf008226232956ee5dc975f08cd88215aa198f2
7
+ data.tar.gz: 2940dd71610ea52f3c18ea942f0a2fd4122028f9c1c0bce5986506501c24c5603d981406e997b662e68986411244db442747e453ff65a49431551d56d8da0eac
data/CHANGELOG.md CHANGED
@@ -1 +1 @@
1
- See the Release Notes under https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/doc/release_notes
1
+ See the Release Notes under https://gitlab.com/os85/rodauth-oauth/-/tree/master/doc/release_notes
@@ -90,6 +90,10 @@ The client secret is hashed (with bcrypt) before being stored, by default. While
90
90
  oauth_applications_client_secret_hash_column nil
91
91
  ```
92
92
 
93
+ ## oauth applications: oauth_applications_homepage_url_column no longer required
94
+
95
+ The homepage url is no longer considered a require prooperty of an OAuth client application.
96
+
93
97
  ## oauth grants: access token and refresh token hashed by default
94
98
 
95
99
  access token and refresh token columns are now hashed by default, and point to the same column as the main counterpart:
@@ -205,6 +209,14 @@ JWKs URI endpoint has been moved to its plugin. If you require this functionalit
205
209
  enable :oauth_jwt, :oauth_jwt_jwks
206
210
  ```
207
211
 
212
+ ## OIDC RP-initiated logout segregated in its plugin
213
+
214
+ It was previously being loaded in the `:oidc` plugin by default. If you require this funtionality, enable the plugin:
215
+
216
+ ```ruby
217
+ enable :oidc_rp_initiated_logout
218
+ ```
219
+
208
220
  ## routing functions renamed
209
221
 
210
222
  Previously, loading well-known routes, the oauth server metadata, or oauth application/tokens (now grants) management dashboard implied calling a function on roda to load those routes. These have been renamed:
data/README.md CHANGED
@@ -1,11 +1,25 @@
1
1
  # Rodauth::Oauth
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rodauth-oauth.svg)](http://rubygems.org/gems/rodauth-oauth)
4
- [![pipeline status](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/rodauth-oauth/pipelines?page=1&scope=all&ref=master)
5
- [![coverage report](https://gitlab.com/honeyryderchuck/rodauth-oauth/badges/master/coverage.svg?job=coverage)](https://honeyryderchuck.gitlab.io/rodauth-oauth/coverage/#_AllFiles)
4
+ [![pipeline status](https://gitlab.com/os85/rodauth-oauth/badges/master/pipeline.svg)](https://gitlab.com/os85/rodauth-oauth/pipelines?page=1&scope=all&ref=master)
5
+ [![coverage report](https://gitlab.com/os85/rodauth-oauth/badges/master/coverage.svg?job=coverage)](https://os85.gitlab.io/rodauth-oauth/coverage/#_AllFiles)
6
6
 
7
7
  This is an extension to the `rodauth` gem which implements the [OAuth 2.0 framework](https://tools.ietf.org/html/rfc6749) for an authorization server.
8
8
 
9
+ ## Certification
10
+ [<img width="184" height="96" align="right" src="/openid-certified.jpg" alt="OpenID Certification">](https://openid.net/certification/)
11
+
12
+ `rodauth-oauth` is [certified](https://openid.net/certification/) for the following profiles of the OpenID Connect™ protocol:
13
+
14
+ * Basic OP
15
+ * Implicit OP
16
+ * Hybrid OP
17
+ * Config OP
18
+ * Dynamic OP
19
+ * Form Post OP
20
+
21
+ (it also passes the conformance tests for the RP-Initiated Logout OP).
22
+
9
23
  ## Features
10
24
 
11
25
  This gem implements the following RFCs and features of OAuth:
@@ -35,11 +49,12 @@ This gem implements the following RFCs and features of OAuth:
35
49
 
36
50
  It also implements the [OpenID Connect layer](https://openid.net/connect/) (via the `openid` feature) on top of the OAuth features it provides, including:
37
51
 
38
- * [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html);
39
- * [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0-29.html);
40
- * [OpenID Multiple Response Types](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html);
41
- * [OpenID Connect Dynamic Client Registration](https://openid.net/specs/openid-connect-registration-1_0.html);
42
- * [RP Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html);
52
+ * `oidc`
53
+ * [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html);
54
+ * [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0-29.html);
55
+ * [OpenID Multiple Response Types](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html);
56
+ * `oidc_dynamic_client_registration` - [OpenID Connect Dynamic Client Registration](https://openid.net/specs/openid-connect-registration-1_0.html);
57
+ * `oidc_rp_initiated_logout` - [RP Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html);
43
58
 
44
59
  This gem supports also rails (through [rodauth-rails]((https://github.com/janko/rodauth-rails))).
45
60
 
@@ -64,10 +79,10 @@ Or install it yourself as:
64
79
  ## Resources
65
80
  | | |
66
81
  | ------------- | ----------------------------------------------------------- |
67
- | Website | https://honeyryderchuck.gitlab.io/rodauth-oauth/ |
68
- | Documentation | https://honeyryderchuck.gitlab.io/rodauth-oauth/rdoc/ |
69
- | Wiki | https://gitlab.com/honeyryderchuck/rodauth-oauth/wikis/home |
70
- | CI | https://gitlab.com/honeyryderchuck/rodauth-oauth/pipelines |
82
+ | Website | https://os85.gitlab.io/rodauth-oauth/ |
83
+ | Documentation | https://os85.gitlab.io/rodauth-oauth/rdoc/ |
84
+ | Wiki | https://gitlab.com/os85/rodauth-oauth/wikis/home |
85
+ | CI | https://gitlab.com/os85/rodauth-oauth/pipelines |
71
86
 
72
87
  ## Articles
73
88
 
@@ -131,12 +146,12 @@ end
131
146
 
132
147
  ### Example (TL;DR)
133
148
 
134
- Just [check our example applications](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/examples/).
149
+ Just [check our example applications](https://gitlab.com/os85/rodauth-oauth/-/tree/master/examples/).
135
150
 
136
151
 
137
152
  ### Database migrations
138
153
 
139
- You have to generate database tables for accounts, oauth applications, grants and tokens. In order for you to hit the ground running, [here's a set of migrations (using `sequel`) to generate the needed tables](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/test/migrate) (omit the first 2 if you already have account tables, and [follow recommendations from rodauth accordingly](https://github.com/jeremyevans/rodauth)).
154
+ You have to generate database tables for accounts, oauth applications, grants and tokens. In order for you to hit the ground running, [here's a set of migrations (using `sequel`) to generate the needed tables](https://gitlab.com/os85/rodauth-oauth/-/tree/master/test/migrate) (omit the first 2 if you already have account tables, and [follow recommendations from rodauth accordingly](https://github.com/jeremyevans/rodauth)).
140
155
 
141
156
  You can change column names or even use existing tables, however, be aware that you'll have to define new column accessors at the `rodauth` plugin declaration level. Let's say, for instance, you'd like to change the `oauth_grants` table name to `access_grants`, and it's `code` column to `authorization_code`; then, you'd have to do the following:
142
157
 
@@ -269,7 +284,7 @@ end
269
284
 
270
285
  `rodauth-oauth` supports translating all user-facing text found in all pages and forms, by integrating with [rodauth-i18n](https://github.com/janko/rodauth-i18n). Just set it up in your application and `rodauth` configuration.
271
286
 
272
- Default translations shipping with `rodauth-oauth` can be found [in this directory](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/locales). If they're not available for the languages you'd like to support, consider getting them translated from the english text, and contributing them to this repository via a Merge Request.
287
+ Default translations shipping with `rodauth-oauth` can be found [in this directory](https://gitlab.com/os85/rodauth-oauth/-/tree/master/locales). If they're not available for the languages you'd like to support, consider getting them translated from the english text, and contributing them to this repository via a Merge Request.
273
288
 
274
289
  (This feature is available since `v0.7`.)
275
290
 
@@ -288,4 +303,4 @@ After checking out the repo, run `bundle install` to install dependencies. Then,
288
303
 
289
304
  ## Contributing
290
305
 
291
- Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/honeyryderchuck/rodauth-oauth.
306
+ Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/os85/rodauth-oauth.
@@ -12,9 +12,9 @@ plugin :rodauth do
12
12
  end
13
13
  ```
14
14
 
15
- For more info about integrating it, [check the wiki](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/home#openid-connect-since-v01).
15
+ For more info about integrating it, [check the wiki](https://gitlab.com/os85/rodauth-oauth/-/wikis/home#openid-connect-since-v01).
16
16
 
17
- It supports omniauth openID integrations out-of-the-box, [check the OpenID example, which integrates with omniauth_openid_connect](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/examples).
17
+ It supports omniauth openID integrations out-of-the-box, [check the OpenID example, which integrates with omniauth_openid_connect](https://gitlab.com/os85/rodauth-oauth/-/tree/master/examples).
18
18
 
19
19
  #### Improvements
20
20
 
@@ -12,7 +12,7 @@ plugin :rodauth do
12
12
  end
13
13
  ```
14
14
 
15
- For more info about integrating it, [check the wiki](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/SAML-Assertion-Access-Tokens).
15
+ For more info about integrating it, [check the wiki](https://gitlab.com/os85/rodauth-oauth/-/wikis/SAML-Assertion-Access-Tokens).
16
16
 
17
17
  ##### Supporting rotating keys
18
18
 
@@ -7,7 +7,7 @@
7
7
  #### Improvements
8
8
 
9
9
 
10
- * Support for the OIDC authorize [`prompt` parameter](https://openid.net/specs/openid-connect-core-1_0.html) (sectionn 3.1.2.1). It supports the `none`, `login` and `consent` out-of-the-box, while providing support for `select-account` when paired with [rodauth-select-account, a rodauth feature to handle multiple accounts in the same session](https://gitlab.com/honeyryderchuck/rodauth-select-account).
10
+ * Support for the OIDC authorize [`prompt` parameter](https://openid.net/specs/openid-connect-core-1_0.html) (sectionn 3.1.2.1). It supports the `none`, `login` and `consent` out-of-the-box, while providing support for `select-account` when paired with [rodauth-select-account, a rodauth feature to handle multiple accounts in the same session](https://gitlab.com/os85/rodauth-select-account).
11
11
 
12
12
  * Refresh Tokens are now expirable. The refresh token expiration period is governed by the `oauth_refresh_token_expires_in` option (default: 1 year), and is the period for which a refresh token can be used after its respective access token expired.
13
13
 
@@ -2,10 +2,10 @@
2
2
 
3
3
  #### RP-Initiated Logout
4
4
 
5
- The `:oidc` plugin can now do [RP-Initiated Logout](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/RP-Initiated-Logout). It's disabled by default, so read the docs to learn how to enable it.
5
+ The `:oidc` plugin can now do [RP-Initiated Logout](https://gitlab.com/os85/rodauth-oauth/-/wikis/RP-Initiated-Logout). It's disabled by default, so read the docs to learn how to enable it.
6
6
 
7
7
  #### Security
8
8
 
9
9
  The `:oauth_jwt` (and by association, `:oidc`) plugin(s) verifies the claims of used JWT tokens. This is a **very important security fix**, as without it, there is no protection against replay attacks and other types of misuse of the JWT token.
10
10
 
11
- A new auth method, `generate_jti(claims)`, was [added to the list of oauth_jwt plugin options](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/JWT-Access-Tokens#rodauth-options). By default, it'll hash the `aud` and `iat` claims together, but you can overwrite how this is done.
11
+ A new auth method, `generate_jti(claims)`, was [added to the list of oauth_jwt plugin options](https://gitlab.com/os85/rodauth-oauth/-/wikis/JWT-Access-Tokens#rodauth-options). By default, it'll hash the `aud` and `iat` claims together, but you can overwrite how this is done.
@@ -4,7 +4,7 @@
4
4
 
5
5
  * Device code grant
6
6
 
7
- `rodauth-oauth` now supports the [Device code grant RFC](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/Device-Grant), via the `oauth_device_grant` feature.
7
+ `rodauth-oauth` now supports the [Device code grant RFC](https://gitlab.com/os85/rodauth-oauth/-/wikis/Device-Grant), via the `oauth_device_grant` feature.
8
8
 
9
9
  * OAuth Tokens Management
10
10
 
@@ -12,7 +12,7 @@ An OAuth Tokens Management Dashboard is now provided (via `r.oauth_tokens` call
12
12
 
13
13
  * Assertion Framework (+ SAML and JWT Bearer Grant)
14
14
 
15
- A new plugin, `oauth_assertion_base`, was introduced to provide a baseline for implementing custom Bearer Assertion as per the [OAuth Client Assertion Framework RFC](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/Client-Assertion-Framework). This in turn was used to refactor and reintroduce the [oauth_saml_bearer_grant](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/SAML-Bearer-Assertions) and the [oauth_jwt_bearer_grant](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/JWT-Bearer-Assertions) features, which implement the respective and most recent version of the assertion RFCs.
15
+ A new plugin, `oauth_assertion_base`, was introduced to provide a baseline for implementing custom Bearer Assertion as per the [OAuth Client Assertion Framework RFC](https://gitlab.com/os85/rodauth-oauth/-/wikis/Client-Assertion-Framework). This in turn was used to refactor and reintroduce the [oauth_saml_bearer_grant](https://gitlab.com/os85/rodauth-oauth/-/wikis/SAML-Bearer-Assertions) and the [oauth_jwt_bearer_grant](https://gitlab.com/os85/rodauth-oauth/-/wikis/JWT-Bearer-Assertions) features, which implement the respective and most recent version of the assertion RFCs.
16
16
 
17
17
  (as a result, `oauth_saml` was removed, which implemented a very old draft version of the SAML Bearer spec).
18
18
 
@@ -0,0 +1,79 @@
1
+ ## 1.0.0 (15/12/2022)
2
+
3
+ ## Highlights
4
+
5
+ rodauth-oauth is now [OpenID certified](https://openid.net/certification/) for the following certification profiles:
6
+
7
+ * Basic OP
8
+ * Implicit OP
9
+ * Hybrid OP
10
+ * Config OP
11
+ * Dynamic OP
12
+ * Form Post OP
13
+
14
+ and passes the conformance tests for RP-Initiated Logout OP.
15
+
16
+ The OIDC server used to run the test can be found [here](https://gitlab.com/os85/rodauth-oauth/-/blob/master/examples/oidc/authentication_server.rb) and deployed [here](https://rodauth-oauth-oidc.onrender.com).
17
+
18
+ ### Breaking changes
19
+
20
+ The full description of breaking changes, and suggestions on how to make the migration smoother, can be found in the [migration guide](https://gitlab.com/os85/rodauth-oauth/-/blob/6465b8522a78cf0037a55d3d4b81f68f7811be68/MIGRATION-GUIDE-v1.md).
21
+
22
+ A short list of the main highlights:
23
+
24
+
25
+ * Ruby 2.5 or higher is required.
26
+ * `oauth_http_mac` feature removed.
27
+ * `oauth_tokens` table (and resource) were removed (only `oauth_applications` and `oauth_grants`, access and refresh tokens are now properties of the latter).
28
+ * access and refresh tokens hashed by default when stored in the database.
29
+ * default oauth response mode is `"form_post"`.
30
+ * oauth specific features require explicit enablement of respective features (no more `enable :oauth`)
31
+ * refresh token policy is "rotation" by default
32
+ * homepage url is no longer a client application required property.
33
+ * OIDC RP-initiated logout extracted into `oidc_rp_initiated_logout` feature.
34
+
35
+ ### Features
36
+
37
+ The following helpers are exposed in the `rodauth` object:
38
+
39
+ * `current_oauth_account` - returns the dataset row for the `rodauth` account associated to an oauth access token in the "authorization" header.
40
+ * `current_oauth_application` - returns the dataset row for the oauth application associated to an oauth access token in the "authorization" header.
41
+
42
+ When used in `rails` via `rodauth-rails`, both are exposed directly as controller helpers.
43
+
44
+ #### `oauth_resource_server` plugin
45
+
46
+ This plugin can be used as a convenience when configuring resource servers.
47
+
48
+ #### JAR support for request_uri query param
49
+
50
+ The `oauth_jwt_secured_authorization_request` plugin now supports a `request_uri` query param as well.
51
+
52
+ #### OIDC features
53
+
54
+ * The `oidc` plugin supports [essential claims](https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter), via the `claims` authorization request query parameter.
55
+ * id token built with `"c_hash"` and `"at_hash"` claims when they should.
56
+
57
+ ### Improvements
58
+
59
+ * `:oauth_introspect` plugin: OAuth introspection endpoint exposes the token's `"username"` claim.
60
+ * endpoint client authentication supports "client credentials grant" access tokens.
61
+ * `acr_values_supported` exposed in the openid configuration.
62
+ * `oauth_request_object_signing_alg_allow_none` enables `"none"` as an accepted request object signing alg when `true` (`false` by default).
63
+ * OIDC `offline_access` supported.
64
+
65
+ ### Bugfixes
66
+
67
+ * fixed `oidc` calculation of `"auth_time"` claim.
68
+ * JWT: "sub" is now always a string.
69
+ * `response_type` is now an authorization request required parameter (as per the RFC).
70
+ * `state` is now passed along when redirecting from authorization requests with `error`;
71
+ * access token can now be read from POST body or GET query params (as per the RFC).
72
+ * id token no longer shipping with claims with `null` value;
73
+ * id token no longer encoding claims by default (only when `response_type=id_token`, as per the RFC).
74
+ * support "JWT without kid" when doing jwt decoding for JWT tokens not generated in the provider (such as request objects).
75
+ * Set `iss` and `aud` claims in the Userinfo JWT response.
76
+ * Make sure errors are also delivered via form POST, when `response_mode=form_post`.
77
+ * Authorization request now shows an error page when `response_type` or `client_id` are missing, or `redirect_uri` is missing or invalid; a new `"authorize_error"` template is invoked in such cases.
78
+ * oidc: nonce present in id token when using the "id_token token" response type.
79
+ * error parameter delivered in URL fragment when failing an implicit grant autorization request.
@@ -2,7 +2,9 @@
2
2
  <% if rodauth.oauth_application[rodauth.oauth_applications_logo_uri_column] %>
3
3
  <%= image_tag rodauth.oauth_application[rodauth.oauth_applications_logo_uri_column] %>
4
4
  <% end %>
5
- <p class="lead"><%= rodauth.authorize_page_lead(name: link_to(rodauth.oauth_application[rodauth.oauth_applications_name_column], rodauth.oauth_application[rodauth.oauth_applications_homepage_url_column])).html_safe %></p>
5
+ <% application_uri = rodauth.oauth_application[rodauth.oauth_applications_homepage_url_column] %>
6
+ <% application_name = application_uri ? link_to(rodauth.oauth_application[rodauth.oauth_applications_name_column], application_uri) : rodauth.oauth_application[rodauth.oauth_applications_name_column] %>
7
+ <p class="lead"><%= rodauth.authorize_page_lead(name: application_name).html_safe %></p>
6
8
 
7
9
  <div class="list-group">
8
10
  <% if rodauth.oauth_application[rodauth.oauth_applications_tos_uri_column] %>
@@ -26,10 +28,14 @@
26
28
  <h1 class="display-6"><%= rodauth.oauth_grants_scopes_label %></h1>
27
29
 
28
30
  <% rodauth.authorize_scopes.each do |scope| %>
29
- <div class="form-check">
30
- <%= check_box_tag "scope[]", scope, id: scope, class: "form-check-input" %>
31
- <%= label_tag scope, scope, class: "form-check-label" %>
32
- </div>
31
+ <% if rodauth.features.include?(:oidc) && scope == "offline_access" %>
32
+ <%= hidden_field_tag "scope[]", scope %>
33
+ <% else %>
34
+ <div class="form-check">
35
+ <%= check_box_tag "scope[]", scope, id: scope, class: "form-check-input" %>
36
+ <%= label_tag scope, scope, class: "form-check-label" %>
37
+ </div>
38
+ <% end %>
33
39
  <% end %>
34
40
  <%= hidden_field_tag :client_id, params[:client_id] %>
35
41
  <% %i[access_type response_type response_mode state redirect_uri].each do |oauth_param| %>
@@ -51,6 +57,9 @@
51
57
  <% end %>
52
58
  <% end %>
53
59
  <% if rodauth.features.include?(:oidc) %>
60
+ <% if params[:prompt] %>
61
+ <%= hidden_field_tag :prompt, params[:prompt] %>
62
+ <% end %>
54
63
  <% if params[:nonce] %>
55
64
  <%= hidden_field_tag :nonce, params[:nonce] %>
56
65
  <% end %>
@@ -60,13 +69,16 @@
60
69
  <% if params[:claims_locales] %>
61
70
  <%= hidden_field_tag :claims_locales, params[:claims_locales] %>
62
71
  <% end %>
72
+ <% if params[:claims] %>
73
+ <%= hidden_field_tag :claims, sanitize(params[:claims]) %>
74
+ <% end %>
63
75
  <% if params[:acr_values] %>
64
- <%= hidden_field_tag :acr, params[:acr_values] %>
76
+ <%= hidden_field_tag :acr_values, params[:acr_values] %>
65
77
  <% end %>
66
78
  <% end %>
67
79
  </div>
68
80
  <p class="text-center">
69
81
  <%= submit_tag rodauth.oauth_authorize_button, class: "btn btn-outline-primary" %>
70
- <%= link_to rodauth.oauth_cancel_button, "#{rodauth.redirect_uri}?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request#{"&state=\#{rodauth.state}" if params[:state] }", class: "btn btn-outline-danger" %>
82
+ <%= link_to rodauth.oauth_cancel_button, "#{rodauth.redirect_uri}?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request#{"&state=\#{CGI.escape(rodauth.state)}" if params[:state] }", class: "btn btn-outline-danger" %>
71
83
  </p>
72
84
  <% end %>
@@ -0,0 +1,10 @@
1
+ <div class="container">
2
+ <div class="alert alert-danger">
3
+ <p>
4
+ <%= @error %>%
5
+ </p>
6
+ </div>
7
+ <p class="text-center">
8
+ <%= link_to rodauth.oauth_cancel_button, @back_url, class: "btn btn-outline-danger" %>
9
+ </p>
10
+ </div>
@@ -5,42 +5,48 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
5
5
  t.foreign_key :accounts, column: :account_id
6
6
  t.string :name, null: false
7
7
  t.string :description, null: true
8
- t.string :homepage_url, null: false
8
+ t.string :homepage_url, null: true
9
9
  t.string :redirect_uri, null: false
10
10
  t.string :client_id, null: false, index: { unique: true }
11
11
  t.string :client_secret, null: false, index: { unique: true }
12
12
  t.string :scopes, null: false
13
13
  t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
14
- # extra params
15
- # t.string :token_endpoint_auth_method, null: true
16
- # t.string :grant_types, null: true
17
- # t.string :response_types, null: true
18
- # t.string :client_uri, null: true
19
- # t.string :logo_uri, null: true
20
- # t.string :tos_uri, null: true
21
- # t.string :policy_uri, null: true
22
- # t.string :jwks_uri, null: true
23
- # t.string :jwks, null: true
24
- # t.string :contacts, null: true
25
- # t.string :software_id, null: true
26
- # t.string :software_version, null: true
27
- # oidc extra params
28
- # t.string :sector_identifier_uri, null: true
29
- # t.string :application_type, null: true
30
- # t.string :subject_type, null: true
31
- # t.string :id_token_signed_response_alg, null: true
32
- # t.string :id_token_encrypted_response_alg, null: true
33
- # t.string :id_token_encrypted_response_enc, null: true
34
- # t.string :userinfo_signed_response_alg, null: true
35
- # t.string :userinfo_encrypted_response_alg, null: true
36
- # t.string :userinfo_encrypted_response_enc, null: true
37
- # t.string :request_object_signing_alg, null: true
38
- # t.string :request_object_encryption_alg, null: true
39
- # t.string :request_object_encryption_enc, null: true
40
- # JWT/OIDC per application signing verification
41
- # t.text :jwt_public_key, null: true
42
- # RP-initiated logout
43
- # t.string :post_logout_redirect_uri, null: false
14
+
15
+ # :oauth_dynamic_client_configuration enabled, extra optional params
16
+ t.string :token_endpoint_auth_method, null: true
17
+ t.string :grant_types, null: true
18
+ t.string :response_types, null: true
19
+ t.string :client_uri, null: true
20
+ t.string :logo_uri, null: true
21
+ t.string :tos_uri, null: true
22
+ t.string :policy_uri, null: true
23
+ t.string :jwks_uri, null: true
24
+ t.string :jwks, null: true
25
+ t.string :contacts, null: true
26
+ t.string :software_id, null: true
27
+ t.string :software_version, null: true
28
+
29
+ # :oidc_dynamic_client_configuration enabled, extra optional params
30
+ t.string :sector_identifier_uri, null: true
31
+ t.string :application_type, null: true
32
+
33
+ # :oidc enabled
34
+ t.string :subject_type, null: true
35
+ t.string :id_token_signed_response_alg, null: true
36
+ t.string :id_token_encrypted_response_alg, null: true
37
+ t.string :id_token_encrypted_response_enc, null: true
38
+ t.string :userinfo_signed_response_alg, null: true
39
+ t.string :userinfo_encrypted_response_alg, null: true
40
+ t.string :userinfo_encrypted_response_enc, null: true
41
+
42
+ # :oauth_jwt_secured_authorization_request
43
+ t.string :request_object_signing_alg, null: true
44
+ t.string :request_object_encryption_alg, null: true
45
+ t.string :request_object_encryption_enc, null: true
46
+ t.string :request_uris, null: true
47
+
48
+ # :oidc_rp_initiated_logout enabled
49
+ t.string :post_logout_redirect_uris, null: false
44
50
  end
45
51
 
46
52
  create_table :oauth_grants do |t|
@@ -58,19 +64,24 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
58
64
  t.datetime :revoked_at
59
65
  t.string :scopes, null: false
60
66
  t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
61
- # for using access_types
62
67
  t.string :access_type, null: false, default: "offline"
63
- # uncomment to enable PKCE
64
- # t.string :code_challenge
65
- # t.string :code_challenge_method
66
- # device code grant
67
- # t.string :user_code, null: true, unique: true
68
- # t.datetime :last_polled_at, null: true
69
- # when using :oauth_resource_indicators feature
70
- # t.string :resource
71
- # uncomment to use OIDC nonce
72
- # t.string :nonce
73
- # t.string :acr
68
+
69
+ # :oauth_pkce enabled
70
+ t.string :code_challenge
71
+ t.string :code_challenge_method
72
+
73
+ # :oauth_device_code_grant enabled
74
+ t.string :user_code, null: true, unique: true
75
+ t.datetime :last_polled_at, null: true
76
+
77
+ # :resource_indicators enabled
78
+ t.string :resource
79
+
80
+ # :oidc enabled
81
+ t.string :nonce
82
+ t.string :acr
83
+ t.string :claims_locales
84
+ t.string :claims
74
85
  end
75
86
  end
76
87
  end
@@ -165,10 +165,10 @@ module Rodauth
165
165
  value.each do |uri|
166
166
  next if uri.empty?
167
167
 
168
- set_field_error(key, invalid_url_message) unless check_valid_uri?(uri)
168
+ set_field_error(key, invalid_url_message) unless check_valid_no_fragment_uri?(uri)
169
169
  end
170
170
  else
171
- set_field_error(key, invalid_url_message) unless check_valid_uri?(value)
171
+ set_field_error(key, invalid_url_message) unless check_valid_no_fragment_uri?(value)
172
172
  end
173
173
  elsif key == oauth_application_scopes_param
174
174
 
@@ -25,9 +25,9 @@ module Rodauth
25
25
  def validate_authorize_params
26
26
  super
27
27
 
28
- return unless (response_mode = param_or_nil("response_mode")) && !oauth_response_modes_supported.include?(response_mode)
28
+ response_mode = param_or_nil("response_mode")
29
29
 
30
- redirect_response_error("invalid_request")
30
+ redirect_response_error("invalid_request") if response_mode && !oauth_response_modes_supported.include?(response_mode)
31
31
  end
32
32
 
33
33
  def validate_token_params
@@ -46,7 +46,6 @@ module Rodauth
46
46
 
47
47
  case response_type
48
48
  when "code", nil
49
- response_mode ||= oauth_response_mode
50
49
  response_params.replace(_do_authorize_code)
51
50
  end
52
51
 
@@ -68,7 +67,7 @@ module Rodauth
68
67
  redirect_url = URI.parse(redirect_uri)
69
68
  case mode
70
69
  when "query"
71
- params = params.map { |k, v| "#{k}=#{v}" }
70
+ params = params.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }
72
71
  params << redirect_url.query if redirect_url.query
73
72
  redirect_url.query = params.join("&")
74
73
  redirect(redirect_url.to_s)
@@ -80,7 +79,7 @@ module Rodauth
80
79
  <form method="post" action="#{redirect_uri}">
81
80
  #{
82
81
  params.map do |name, value|
83
- "<input type=\"hidden\" name=\"#{name}\" value=\"#{scope.h(value)}\" />"
82
+ "<input type=\"hidden\" name=\"#{scope.h(name)}\" value=\"#{scope.h(value)}\" />"
84
83
  end.join
85
84
  }
86
85
  <input type="submit" class="btn btn-outline-primary" value="#{scope.h(oauth_authorize_post_button)}"/>
@@ -91,11 +90,36 @@ module Rodauth
91
90
  end
92
91
  end
93
92
 
93
+ def _redirect_response_error(redirect_url, query_params)
94
+ response_mode = param_or_nil("response_mode") || oauth_response_mode
95
+
96
+ case response_mode
97
+ when "form_post"
98
+ response["Content-Type"] = "text/html"
99
+ response.write <<-FORM
100
+ <html>
101
+ <head><title></title></head>
102
+ <body onload="javascript:document.forms[0].submit()">
103
+ <form method="post" action="#{redirect_uri}">
104
+ #{
105
+ query_params.map do |name, value|
106
+ "<input type=\"hidden\" name=\"#{name}\" value=\"#{scope.h(value)}\" />"
107
+ end.join
108
+ }
109
+ </form>
110
+ </body>
111
+ </html>
112
+ FORM
113
+ request.halt
114
+ else
115
+ super
116
+ end
117
+ end
118
+
94
119
  def create_token(grant_type)
95
120
  return super unless supported_grant_type?(grant_type, "authorization_code")
96
121
 
97
122
  grant_params = {
98
- oauth_grants_type_column => grant_type,
99
123
  oauth_grants_code_column => param("code"),
100
124
  oauth_grants_redirect_uri_column => param("redirect_uri"),
101
125
  oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column]
@@ -107,7 +131,7 @@ module Rodauth
107
131
  def check_valid_response_type?
108
132
  response_type = param_or_nil("response_type")
109
133
 
110
- response_type.nil? || response_type == "code" || response_type == "none" || super
134
+ response_type == "code" || response_type == "none" || super
111
135
  end
112
136
 
113
137
  def oauth_server_metadata_body(*)