rodauth-oauth 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -424
  3. data/README.md +26 -389
  4. data/doc/release_notes/0_0_1.md +3 -0
  5. data/doc/release_notes/0_0_2.md +15 -0
  6. data/doc/release_notes/0_0_3.md +31 -0
  7. data/doc/release_notes/0_0_4.md +36 -0
  8. data/doc/release_notes/0_0_5.md +36 -0
  9. data/doc/release_notes/0_0_6.md +21 -0
  10. data/doc/release_notes/0_1_0.md +44 -0
  11. data/doc/release_notes/0_2_0.md +43 -0
  12. data/doc/release_notes/0_3_0.md +28 -0
  13. data/doc/release_notes/0_4_0.md +18 -0
  14. data/doc/release_notes/0_4_1.md +9 -0
  15. data/doc/release_notes/0_4_2.md +5 -0
  16. data/doc/release_notes/0_4_3.md +3 -0
  17. data/doc/release_notes/0_5_0.md +11 -0
  18. data/doc/release_notes/0_5_1.md +13 -0
  19. data/doc/release_notes/0_6_0.md +9 -0
  20. data/doc/release_notes/0_6_1.md +6 -0
  21. data/doc/release_notes/0_7_0.md +20 -0
  22. data/doc/release_notes/0_7_1.md +10 -0
  23. data/doc/release_notes/0_7_2.md +21 -0
  24. data/doc/release_notes/0_7_3.md +10 -0
  25. data/doc/release_notes/0_7_4.md +5 -0
  26. data/doc/release_notes/0_8_0.md +37 -0
  27. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +3 -3
  28. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_search.html.erb +11 -0
  29. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_verification.html.erb +20 -0
  30. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/new_oauth_application.html.erb +22 -10
  31. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application.html.erb +11 -5
  32. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_tokens.html.erb +38 -0
  33. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_applications.html.erb +5 -5
  34. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_tokens.html.erb +11 -15
  35. data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +9 -1
  36. data/lib/rodauth/features/oauth.rb +3 -1418
  37. data/lib/rodauth/features/oauth_application_management.rb +209 -0
  38. data/lib/rodauth/features/oauth_assertion_base.rb +96 -0
  39. data/lib/rodauth/features/oauth_authorization_code_grant.rb +249 -0
  40. data/lib/rodauth/features/oauth_authorization_server.rb +0 -0
  41. data/lib/rodauth/features/oauth_base.rb +735 -0
  42. data/lib/rodauth/features/oauth_device_grant.rb +221 -0
  43. data/lib/rodauth/features/oauth_http_mac.rb +3 -21
  44. data/lib/rodauth/features/oauth_implicit_grant.rb +59 -0
  45. data/lib/rodauth/features/oauth_jwt.rb +37 -60
  46. data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +59 -0
  47. data/lib/rodauth/features/oauth_pkce.rb +98 -0
  48. data/lib/rodauth/features/oauth_resource_server.rb +21 -0
  49. data/lib/rodauth/features/oauth_saml_bearer_grant.rb +102 -0
  50. data/lib/rodauth/features/oauth_token_introspection.rb +108 -0
  51. data/lib/rodauth/features/oauth_token_management.rb +77 -0
  52. data/lib/rodauth/features/oauth_token_revocation.rb +109 -0
  53. data/lib/rodauth/features/oidc.rb +4 -3
  54. data/lib/rodauth/oauth/database_extensions.rb +15 -2
  55. data/lib/rodauth/oauth/refinements.rb +48 -0
  56. data/lib/rodauth/oauth/version.rb +1 -1
  57. data/locales/en.yml +28 -12
  58. data/templates/authorize.str +7 -7
  59. data/templates/client_secret_field.str +2 -2
  60. data/templates/description_field.str +1 -1
  61. data/templates/device_search.str +11 -0
  62. data/templates/device_verification.str +24 -0
  63. data/templates/homepage_url_field.str +2 -2
  64. data/templates/jws_jwk_field.str +4 -0
  65. data/templates/jwt_public_key_field.str +4 -0
  66. data/templates/name_field.str +1 -1
  67. data/templates/new_oauth_application.str +9 -0
  68. data/templates/oauth_application.str +7 -3
  69. data/templates/oauth_application_oauth_tokens.str +51 -0
  70. data/templates/oauth_applications.str +2 -2
  71. data/templates/oauth_tokens.str +9 -11
  72. data/templates/redirect_uri_field.str +2 -2
  73. metadata +71 -3
  74. data/lib/rodauth/features/oauth_saml.rb +0 -104
@@ -0,0 +1,43 @@
1
+ ### 0.2.0 (9/9/2020)
2
+
3
+ #### Features
4
+
5
+ ##### SAML Assertion Grant Type
6
+
7
+ `rodauth-auth` now supports using a SAML Assertion to request for an Access token.In order to enable, you have to:
8
+
9
+ ```ruby
10
+ plugin :rodauth do
11
+ enable :oauth_saml
12
+ end
13
+ ```
14
+
15
+ For more info about integrating it, [check the wiki](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/wikis/SAML-Assertion-Access-Tokens).
16
+
17
+ ##### Supporting rotating keys
18
+
19
+ At some point, you'll want to replace the pkeys and algorithm used to generate and verify the JWT access tokens, but you want to keep validating previously-distributed JWT tokens, at least until they expire. Now you can, via two new options, `oauth_jwt_legacy_public_key` and `oauth_jwt_legacy_algorithm`, which will be declared in the JWKs URI and used to verify access tokens.
20
+
21
+
22
+ ##### Reuse access tokens
23
+
24
+ If the `oauth_reuse_access_token` is set, if there's already an existing valid access token, any new grant for the same application / account / scope will keep the same access token. This can be helpful in scenarios where one wants the same access token distributed across devices.
25
+
26
+ ##### require_authorizable_account
27
+
28
+ The method used to verify access to the authorize flow is called `require_authorizable_account`. By default, it checks if a user is logged in by using rodauth's own `require_account`. This is the method you'd want to redefine in order to augment these requirements, i.e. request 2fa authentication.
29
+
30
+ #### Improvements
31
+
32
+ Expired and revoked access tokens end up generating a lot of garbage, which will have to be periodically cleaned up. You can mitigate this now by setting a uniqueness index for a group of columns, i.e. if you set a uniqueness index for the `oauth_application_id/account_id/scopes` column, `rodauth-oauth` will transparently reuse the same db entry to store the new access token. If setting some other type of uniqueness index, make sure to update the option `oauth_tokens_unique_columns` (the array of columns from the uniqueness index).
33
+
34
+ #### Bugfixes
35
+
36
+ Calling `before_*_route` callbacks appropriately.
37
+
38
+ Fixed some mishandling of HTTP headers when in in resource-server mode.
39
+
40
+ #### Chore
41
+
42
+ * 97.7% test coverage;
43
+ * `rodauth-oauth` CI tests run against sqlite, postgresql and mysql.
@@ -0,0 +1,28 @@
1
+ ### 0.3.0 (8/10/2020)
2
+
3
+ #### Features
4
+
5
+ * `oauth_refresh_token_protection_policy` is a new option, which can be used to set a protection policy around usage of refresh tokens. By default it's `none`, for backwards-compatibility. However, when set to `rotation`, refresh tokens will be "use-once", i.e. a token refresh request will generate a new refresh token. Also, refresh token requests performed with already-used refresh tokens will be interpreted as a security breach, i.e. all tokens linked to the compromised refresh token will be revoked.
6
+
7
+ #### Improvements
8
+
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).
11
+
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
+
14
+ #### Bugfixes
15
+
16
+ * Default Templates now being packaged, as a way to provide a default experience to the OAuth journeys.
17
+
18
+ * fixing metadata urls when plugin loaded with a prefix path (@ianks)
19
+
20
+ * All date/time-based calculations, such as determining an expiration date, or checking if a token has expired, are now performed using database arithmetic operations, using sequel's `date_arithmetic` plugin. This will eliminate subtle bugs, such as when the database timezone is different than the application OS timezone.
21
+
22
+ * OIDC configuration endpoint is now stricter, eliminating JSON metadata inherited from the Oauth metadata endpoint. (@ianks)
23
+
24
+ #### Chore
25
+
26
+ Use `rodauth.convert_timestamp` in the templates, whenever dates are displayed.
27
+
28
+ Set HTTP Cache headers for metadata responses, such as `/.well-known/oauth-authorization-server` and `/.well-known/openid-configuration`, so they can be stored at the edge. The cache will be valid for 1 day (this value isn't set by an option yet).
@@ -0,0 +1,18 @@
1
+ ### 0.4.0 (13/11/2020)
2
+
3
+ #### Features
4
+
5
+ * A new method, `get_additional_param(account, claim)`, is now exposed; this method will be called whenever non-OIDC scopes are requested in the emission of the ID token.
6
+
7
+ * The `form_post` response is now supported, either by passing the `response_mode=form_post` request param in the authorization URL, or by setting `oauth_response_mode "form_post"` option. This improves the overall security of an Authorization server even more, as authorization codes are sent to client applications via a POST request to the redirect URI.
8
+
9
+
10
+ #### Improvements
11
+
12
+ * For the OIDC `address` scope, proper claims are now emitted as per the standard, i.e. the "formatted", "street_address", "locality", "region", "postal_code", "country". These will be the ones referenced in the `get_oidc_param` method.
13
+
14
+ #### Bugfixes
15
+
16
+ * The rails templates were missing declarations from a few params, which made some of the flows (the PKCE for example) not work out-of-the box;
17
+ * rails tests were silently not running in CI;
18
+ * The CI suite was revamped, so that all Oauth tests would be run under rails as well. All versions from rails equal or above 5.0 are now targeted;
@@ -0,0 +1,9 @@
1
+ ### 0.4.1 (24/11/2020)
2
+
3
+ #### Improvements
4
+
5
+ When in "Resource Server" mode, calling `rodauth.authorization_token` will now return an hash of the JSON payload that the Authorization Server responds, and which was already previously used to authorize access to protected resources.
6
+
7
+ #### Bugfixes
8
+
9
+ * An error occurred if the client passed an empty authorization header (`Authorization: ` or `Authorization: Bearer `), causing an unexpected error; It now responds with the proper `401 Unauthorized` status code.
@@ -0,0 +1,5 @@
1
+ ### 0.4.2 (24/11/2020)
2
+
3
+ #### Bugfixes
4
+
5
+ * database extensions were being run in resource server mode, when it's not expected that the oauth db tables are around.
@@ -0,0 +1,3 @@
1
+ ### 0.4.3 (09/12/2020)
2
+
3
+ * Introspection requests made to an Authorization Server in "resource server" mode are not correctly encoding the body using the "application/x-www-form-urlencoded" format.
@@ -0,0 +1,11 @@
1
+ ### 0.5.0 (08/02/2021)
2
+
3
+ #### RP-Initiated Logout
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.
6
+
7
+ #### Security
8
+
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
+
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.
@@ -0,0 +1,13 @@
1
+ ### 0.5.1 (19/03/2021)
2
+
3
+ #### Improvements
4
+
5
+ * Changing "Callback URL" to "Redirect URL" in default templates;
6
+
7
+ #### Bugfixes
8
+
9
+ * (rails integration) Fixed templates location;
10
+ * (rails integration) Fixed migration name from generator;
11
+ * (rails integration) fixed links, html tags, styling and unassigned variables from a few view templates;
12
+ * `oauth_application_path` is now compliant with prefixes and other url helpers, while now having a `oauth_application_url` counterpart;
13
+ * (rails integration) skipping csrf checks for "/userinfo" request (OIDC)
@@ -0,0 +1,9 @@
1
+ ### 0.6.0 (21/05/2021)
2
+
3
+ ### Improvements
4
+
5
+ * RBS signatures
6
+
7
+ ### Chore
8
+
9
+ * Ruby 3 and Truffleruby are now officially supported and tested in CI.
@@ -0,0 +1,6 @@
1
+ ### 0.6.1 (08/09/2021)
2
+
3
+ #### Bugfixes
4
+
5
+ * Fixed rails view templates escaping.
6
+ * Fixed declaration of authorize template in the generator.
@@ -0,0 +1,20 @@
1
+ ### 0.7.0 (02/12/2021)
2
+
3
+ #### Features
4
+
5
+ * Internationalization (i18n) support by hooking on [rodauth-i18n](https://github.com/janko/rodauth-i18n).
6
+ * Sets all text using `translatable_method`.
7
+ * Provides english translations for all `rodauth-oauth` related user facing text.
8
+
9
+ #### Improvements
10
+
11
+ * Enable CORS requests for OpenID configuration endpoint (@ianks)
12
+ * Introspect endpoint now exposes the `exp` token property (@gmanley)
13
+
14
+ #### Bugfixes
15
+
16
+ * on rotation policy, although the first refresh token was invalidated, a new one wasn't being provided. This change allows a new refresh token to be generated and exposed in the response (@gmanley)
17
+
18
+ #### Chore
19
+
20
+ Setting `rodauth` minimal supported version to `2.0.0`.
@@ -0,0 +1,10 @@
1
+ ### 0.7.1 (05/12/2021)
2
+
3
+ #### Improvements
4
+
5
+ * Adapted the `rodauth-i18n` configuration to comply with the guidelines for `v0.2.0` (which is the defacto minimmal supported version).
6
+
7
+ #### Bugfixes
8
+
9
+ * `convert_timestamp` was removed from the templates, as it's private API.
10
+ * Several missing or wrong URLs in templates fixed (authorize form was wrongly processing scopes when none was selected).
@@ -0,0 +1,21 @@
1
+ ### 0.7.2 (14/12/2021)
2
+
3
+ #### Features
4
+
5
+ * Revoking tokens from the OAuth Application management interface (@muellerj)
6
+
7
+ Token revocation was only possible when using the client ID and Secret, to aid "logout" functionality from client applications. Although the admin interface (available via `r.oauth_applications`) displayed a "Revoke" button alongside tokens in the list page, this was not working. The RFC does allow for the use case of application administrators being able to manually revoke tokens (as a result of client support, for example), so this functionality was enabled (only for the oauth application owner, for now).
8
+
9
+ #### Bugfixes
10
+
11
+ Default scope usage related bugfixes:
12
+
13
+ * Improved default scope conversion to avoid nested arrays (@muellerj);
14
+ * Authorize form shows a disabled checkbox and POST's no scope when default scope is to be used (@muellerj);
15
+ * example default scope fixed for example authorization server (should be string) (@muellerj);
16
+ * several param fixes in view templates (@muellerj);
17
+
18
+ OAuth Applications Management fixes:
19
+
20
+ * Access to OAuth Application page is now restricted to app owner;
21
+ * OAuth Applications page now lists the **only** the applications owned by the logged in user;
@@ -0,0 +1,10 @@
1
+ ## 0.7.3 (14/01/2022)
2
+
3
+ #### Bugfixes
4
+
5
+ * fixed generator declarations and views generator, in orderto copy templates and rewrite paths accordingly.
6
+ * update view templates to not use "%%".
7
+
8
+ #### Chore
9
+
10
+ * `rodauth` is now declared as a dependency, with minimum version set `2.0`.
@@ -0,0 +1,5 @@
1
+ ### 0.7.4 (15/01/2022)
2
+
3
+ #### Bugfixes
4
+
5
+ * including missing erb templates in the package.
@@ -0,0 +1,37 @@
1
+ ### 0.8.0 (12/03/2022)
2
+
3
+ #### Features
4
+
5
+ * Device code grant
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.
8
+
9
+ * OAuth Tokens Management
10
+
11
+ An OAuth Tokens Management Dashboard is now provided (via `r.oauth_tokens` call to enable the routes). It allows the logged in account to list and revoke OAuth Tokens which have been issued for its resources.
12
+
13
+ * Assertion Framework (+ SAML and JWT Bearer Grant)
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.
16
+
17
+ (as a result, `oauth_saml` was removed, which implemented a very old draft version of the SAML Bearer spec).
18
+
19
+ #### Improvements
20
+
21
+ The OAuth functionality was refactored from 1 big feature, into several features:
22
+
23
+ * `oauth_base`
24
+ * `oauth_authorization_code_grant`
25
+ * `oauth_implicit_grant`
26
+ * `oauth_device_grant`
27
+ * `oauth_token_introspection`
28
+ * `oauth_token_revocation`
29
+ * `oauth_application_management`
30
+ * `oauth_token_management`
31
+ * `oauth_pkce`
32
+
33
+ They're still loaded together via the `oauth` feature for backwards compatibility. This will change in a major version.
34
+
35
+ #### Bugfixes
36
+
37
+ * `oauth_jwt` integration with the `json-jwt` gem does proper claims validation now;
@@ -2,7 +2,7 @@
2
2
  <p class="lead">The application <%= rodauth.oauth_application[rodauth.oauth_applications_name_column] %> would like to access your data.</p>
3
3
 
4
4
  <div class="form-group">
5
- <h1 class="display-6"><%= rodauth.scopes_label %></h1>
5
+ <h1 class="display-6"><%= rodauth.oauth_tokens_scopes_label %></h1>
6
6
 
7
7
  <% rodauth.scopes.each do |scope| %>
8
8
  <% is_default = scope == rodauth.oauth_application_default_scope %>
@@ -23,7 +23,7 @@
23
23
  <% end %>
24
24
  </div>
25
25
  <p class="text-center">
26
- <%= submit_tag "Authorize", class: "btn btn-outline-primary" %>
27
- <%= link_to "Cancel", "#{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" %>
26
+ <%= submit_tag rodauth.oauth_authorize_button, class: "btn btn-outline-primary" %>
27
+ <%= 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" %>
28
28
  </p>
29
29
  <% end %>
@@ -0,0 +1,11 @@
1
+ <%= form_tag rodauth.device_path, method: :get, class: "form-horizontal", id: "device-search-form" do %>
2
+ <p class="lead">Insert the user code from the device you'd like to authorize.</p>
3
+
4
+ <div class="form-group">
5
+ <%= label_tag "user_code", rodauth.oauth_grant_user_code_label %>
6
+ <%= text_field_tag "user_code", rodauth.param_or_nil(rodauth.oauth_grant_user_code_param), class: "form-control#{' is-invalid' if rodauth.field_error('user_code')}" %>
7
+ </div>
8
+ <p class="text-center">
9
+ <%= submit_tag rodauth.oauth_device_search_button, class: "btn btn-outline-primary" %>
10
+ </p>
11
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <% oauth_grant = rodauth.scope.instance_variable_get(:@oauth_grant) %>
2
+ <%= form_tag rodauth.device_path, method: :post, class: "form-horizontal", id: "device-verification-form" do %>
3
+ <p class="lead">The device with user code <%= oauth_grant[rodauth.oauth_grants_user_code_column] %> would like to access your data.</p>
4
+
5
+ <div class="form-group">
6
+ <h1 class="display-6"><%= rodauth.oauth_tokens_scopes_label %></h1>
7
+
8
+ <ul class="list-group">
9
+ <% oauth_grant[rodauth.oauth_grants_scopes_column].split(rodauth.oauth_scope_separator).each do |scope| %>
10
+ <li class="list-group-item"><%= scope %></li>
11
+ <% end %>
12
+ </ul>
13
+ </div>
14
+ <%= hidden_field_tag :user_code, rodauth.param("user_code") %>
15
+
16
+ <p class="text-center">
17
+ <%= submit_tag rodauth.oauth_device_verification_button, class: "btn btn-outline-primary" %>
18
+ <%= link_to rodauth.oauth_cancel_button, "#{rodauth.device_path}?error=access_denied", class: "btn btn-outline-danger" %>
19
+ </p>
20
+ <% end %>
@@ -1,31 +1,43 @@
1
+ <h2><%= rodauth.new_oauth_application_page_title %></h2>
1
2
  <%= form_tag rodauth.oauth_applications_path, method: :post, class: "form-horizontal" do %>
2
- <h2>Register Oauth Application</h2>
3
3
  <%= rodauth.field_error('scope') %>
4
4
  <div class="form-group">
5
- <%= label_tag "name", "Name" %>
5
+ <%= label_tag "name", rodauth.oauth_applications_name_label %>
6
6
  <%= text_field_tag "name", rodauth.param('name'), class: "form-control#{' is-invalid' if rodauth.field_error('name')}" %>
7
7
  <%= rodauth.field_error('name') %>
8
8
  </div>
9
9
  <div class="form-group">
10
- <%= label_tag "description", "Description" %>
10
+ <%= label_tag "description", rodauth.oauth_applications_description_label %>
11
11
  <%= text_field_tag "description", rodauth.param('description'), class: "form-control#{' is-invalid' if rodauth.field_error('description')}" %>
12
12
  <%= rodauth.field_error('description') %>
13
13
  </div>
14
14
  <div class="form-group">
15
- <%= label_tag "homepage_url", "Homepage URL" %>
16
- <%= text_field_tag "homepage_url", rodauth.param('homepage_url'), class: "form-control#{' is-invalid' if rodauth.field_error('homepage_url')}" %>
15
+ <%= label_tag "homepage_url", rodauth.oauth_applications_homepage_url_label %>
16
+ <%= text_field_tag "homepage_url", rodauth.param('homepage_url'), id: "homepage-url", class: "form-control#{' is-invalid' if rodauth.field_error('homepage_url')}" %>
17
17
  <%= rodauth.field_error('homepage_url') %>
18
18
  </div>
19
19
  <div class="form-group">
20
- <%= label_tag "redirect_uri", "Redirect URL" %>
21
- <%= text_field_tag "redirect_uri", rodauth.param('redirect_uri'), class: "form-control#{' is-invalid' if rodauth.field_error('redirect_uri')}" %>
20
+ <%= label_tag "redirect_uri", rodauth.oauth_applications_redirect_uri_label %>
21
+ <%= text_field_tag "redirect_uri", rodauth.param('redirect_uri'), id: "redirect-uri", class: "form-control#{' is-invalid' if rodauth.field_error('redirect_uri')}" %>
22
22
  <%= rodauth.field_error('redirect_uri') %>
23
23
  </div>
24
24
  <div class="form-group">
25
- <%= label_tag "client_secret", "Secret (make it random and at least 32 character-long)" %>
26
- <%= text_field_tag "client_secret", rodauth.param('client_secret'), class: "form-control#{' is-invalid' if rodauth.field_error('client_secret')}" %>
25
+ <%= label_tag "client_secret", rodauth.oauth_applications_client_secret_label %>
26
+ <%= text_field_tag "client_secret", rodauth.param('client_secret'), id: "client-secret", class: "form-control#{' is-invalid' if rodauth.field_error('client_secret')}" %>
27
27
  <%= rodauth.field_error('client_secret') %>
28
28
  </div>
29
+ <% if rodauth.features.include?(:oauth_jwt) %>
30
+ <div class="form-group">
31
+ <%= label_tag "jws_jwk", rodauth.oauth_applications_jws_jwk_label %>
32
+ <%= text_field_tag "jws_jwk", rodauth.param('jws_jwk'), id: "jws-jwk", class: "form-control#{' is-invalid' if rodauth.field_error('jws_jwk')}" %>
33
+ <%= rodauth.field_error('jws_jwk') %>
34
+ </div>
35
+ <div class="form-group">
36
+ <%= label_tag "jwt_public_key", rodauth.oauth_applications_jwt_public_key_label %>
37
+ <%= text_field_tag "jwt_public_key", rodauth.param('jwt_public_key'), id: "jwt-public-key", class: "form-control#{' is-invalid' if rodauth.field_error('jwt_public_key')}" %>
38
+ <%= rodauth.field_error('jwt_public_key') %>
39
+ </div>
40
+ <% end %>
29
41
  <% rodauth.oauth_application_scopes.each do |scope| %>
30
42
  <div class="form-check">
31
43
  <%= check_box_tag "scopes[]", scope, scope == rodauth.oauth_application_default_scope, id: scope, class: "form-check-input" %>
@@ -33,6 +45,6 @@
33
45
  </div>
34
46
  <% end %>
35
47
  <div class="form-group">
36
- <%= submit_tag "Register", class: "btn btn-primary" %>
48
+ <%= submit_tag rodauth.oauth_application_button, class: "btn btn-primary" %>
37
49
  </div>
38
50
  <% end %>
@@ -3,15 +3,21 @@
3
3
  <h2><%= oauth_application[rodauth.oauth_applications_name_column] %></h2>
4
4
 
5
5
  <dl>
6
- <dt>Description: </dt>
6
+ <dt><%= rodauth.oauth_applications_description_label %>: </dt>
7
7
  <dd><%= oauth_application[rodauth.oauth_applications_description_column] %></dd>
8
- <dt>Homepage URL: </dt>
8
+ <dt><%= rodauth.oauth_applications_homepage_url_label %>: </dt>
9
9
  <dd><%= oauth_application[rodauth.oauth_applications_homepage_url_column] %></dd>
10
- <dt>Client ID: </dt>
10
+ <dt><%= rodauth.oauth_applications_client_id_label %>: </dt>
11
11
  <dd><%= oauth_application[rodauth.oauth_applications_client_id_column] %></dd>
12
- <dt>Redirect URL: </dt>
12
+ <dt><%= rodauth.oauth_applications_redirect_uri_label %>: </dt>
13
13
  <dd><%= oauth_application[rodauth.oauth_applications_redirect_uri_column] %></dd>
14
- <dt>Scopes: </dt>
14
+ <dt><%= rodauth.oauth_applications_scopes_label %>: </dt>
15
15
  <dd><%= oauth_application[rodauth.oauth_applications_scopes_column] %></dd>
16
+ <% if rodauth.features.include?(:oauth_jwt) %>
17
+ <dt><%= rodauth.oauth_applications_jws_jwk_label %>: </dt>
18
+ <dd><%= oauth_application[rodauth.oauth_applications_jws_jwk_column] %></dd>
19
+ <dt><%= rodauth.oauth_applications_jwt_public_key_label %>: </dt>
20
+ <dd><%= oauth_application[rodauth.oauth_applications_jwt_public_key_column] %></dd>
21
+ <% end %>
16
22
  </dl>
17
23
  </div>
@@ -0,0 +1,38 @@
1
+ <% oauth_tokens = rodauth.scope.instance_variable_get(:@oauth_tokens) %>
2
+ <% tokens_count = oauth_tokens.count %>
3
+ <% if tokens_count.zero? %>
4
+ <p>No oauth tokens yet!</p>
5
+ <% else %>
6
+ <table class="table">
7
+ <thead>
8
+ <tr>
9
+ <th scope="col"><=% rodauth.oauth_tokens_token_label %></th>
10
+ <th scope="col"><=% rodauth.oauth_tokens_refresh_token_label %></th>
11
+ <th scope="col"><=% rodauth.oauth_tokens_expires_in_label %></th>
12
+ <th scope="col"><=% rodauth.oauth_tokens_revoked_at_label %></th>
13
+ <th scope="col"><=% rodauth.oauth_tokens_scopes_label %></th>
14
+ <th scope="col"><span class="badge badge-pill badge-dark"><%= tokens_count %></span>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <% oauth_tokens.each do |oauth_token| %>
19
+ <tr>
20
+ <td><code class="token"><%= oauth_token[rodauth.oauth_tokens_token_column] %></code></td>
21
+ <td><code class="token"><%= oauth_token[rodauth.oauth_tokens_refresh_token_column] %></code></td>
22
+ <td><%= oauth_token[rodauth.oauth_tokens_expires_in_column] %></td>
23
+ <td><%= oauth_token[rodauth.oauth_tokens_revoked_at_column] %></td>
24
+ <td><%= oauth_token[rodauth.oauth_tokens_scopes_column] %></td>
25
+ <td>
26
+ <% if !oauth_token[rodauth.oauth_tokens_revoked_at_column] %>
27
+ <%= form_tag rodauth.revoke_path, method: :post do %>
28
+ <%= hidden_field_tag :token_type_hint, "access_token" %>
29
+ <%= hidden_field_tag :token, oauth_token[rodauth.oauth_tokens_token_column] %>
30
+ <%= submit_tag rodauth.oauth_token_revoke_button, class: "btn btn-danger" %>
31
+ <% end %>
32
+ <% end %>
33
+ </td>
34
+ </tr>
35
+ <% end %>
36
+ </tbody>
37
+ </table>
38
+ <% end %>
@@ -1,7 +1,7 @@
1
1
  <% oauth_applications_ds = rodauth.scope.instance_variable_get(:@oauth_applications) %>
2
2
  <% apps_count = oauth_applications_ds.count %>
3
3
  <div class="btn-group" role="group" aria-label="Buttons">
4
- <%= link_to "New Oauth Application", "#{rodauth.oauth_applications_path}/new", class: "btn btn-secondary" %>
4
+ <%= link_to rodauth.new_oauth_application_page_title, "#{rodauth.oauth_applications_path}/new", class: "btn btn-secondary" %>
5
5
  </div>
6
6
  <% if apps_count.zero? %>
7
7
  <p>No oauth applications yet!</p>
@@ -9,9 +9,9 @@
9
9
  <table class="table">
10
10
  <thead>
11
11
  <tr>
12
- <th scope="col">Client ID (<%= apps_count %>)</th>
13
- <th scope="col">Name</th>
14
- <th scope="col">Homepage</th>
12
+ <th scope="col"><%= rodauth.oauth_application_client_id_label %> (<%= apps_count %>)</th>
13
+ <th scope="col"><%= rodauth.oauth_application_name_label %></th>
14
+ <th scope="col"><%= rodauth.oauth_application_homepage_url_label %></th>
15
15
  <th scope="col"></th>
16
16
  </tr>
17
17
  </thead>
@@ -21,7 +21,7 @@
21
21
  <td><%= application[rodauth.oauth_applications_client_id_column] %></td>
22
22
  <td><%= application[rodauth.oauth_applications_name_column] %></td>
23
23
  <td><%= application[rodauth.oauth_applications_homepage_url_column] %></td>
24
- <td><%= link_to "Show", rodauth.oauth_application_path(application[rodauth.oauth_applications_id_column]) %></td>
24
+ <td><%= link_to "Show", rodauth.oauth_application_path(application[rodauth.oauth_applications_id_column]) %></td>
25
25
  </tr>
26
26
  <% end %>
27
27
  </tbody>
@@ -1,34 +1,30 @@
1
- <% oauth_tokens_ds = rodauth.scope.instance_variable_get(:@oauth_tokens) %>
2
- <% tokens_count = oauth_tokens_ds.count %>
1
+ <% oauth_tokens = rodauth.scope.instance_variable_get(:@oauth_tokens) %>
2
+ <% tokens_count = oauth_tokens.count %>
3
3
  <% if tokens_count.zero? %>
4
4
  <p>No oauth tokens yet!</p>
5
5
  <% else %>
6
6
  <table class="table">
7
7
  <thead>
8
8
  <tr>
9
- <th scope="col">Token</th>
10
- <th scope="col">Refresh Token</th>
11
- <th scope="col">Expires in</th>
12
- <th scope="col">Revoked at</th>
13
- <th scope="col">Scopes</th>
9
+ <th scope="col"><=% rodauth.oauth_applications_name_label %></th>
10
+ <th scope="col"><=% rodauth.oauth_tokens_token_label %></th>
11
+ <th scope="col"><=% rodauth.oauth_tokens_refresh_token_label %></th>
12
+ <th scope="col"><=% rodauth.oauth_tokens_expires_in_label %></th>
13
+ <th scope="col"><=% rodauth.oauth_tokens_scopes_label %></th>
14
14
  <th scope="col"><span class="badge badge-pill badge-dark"><%= tokens_count %></span>
15
15
  </tr>
16
16
  </thead>
17
17
  <tbody>
18
- <% oauth_tokens_ds.each do |application| %>
18
+ <% oauth_tokens.each do |oauth_token| %>
19
19
  <tr>
20
+ <td><%= oauth_token[rodauth.oauth_applications_name_column] %></td>
20
21
  <td><code class="token"><%= oauth_token[rodauth.oauth_tokens_token_column] %></code></td>
21
22
  <td><code class="token"><%= oauth_token[rodauth.oauth_tokens_refresh_token_column] %></code></td>
22
23
  <td><%= oauth_token[rodauth.oauth_tokens_expires_in_column] %></td>
23
- <td><%= oauth_token[rodauth.oauth_tokens_revoked_at_column] %></td>
24
24
  <td><%= oauth_token[rodauth.oauth_tokens_scopes_column] %></td>
25
25
  <td>
26
- <% if !oauth_token[rodauth.oauth_tokens_revoked_at_column] %>
27
- <%= form_tag rodauth.revoke_path, method: :post do %>
28
- <%= hidden_field_tag :token_type_hint, "access_token" %>
29
- <%= hidden_field_tag :token, oauth_token[rodauth.oauth_tokens_token_column] %>
30
- <%= submit_tag "Revoke", class: "btn btn-danger" %>
31
- <% end %>
26
+ <%= form_tag rodauth.oauth_token_path(oauth_token[rodauth.oauth_tokens_id_column]), method: :post do %>
27
+ <%= submit_tag rodauth.oauth_token_revoke_button, class: "btn btn-danger" %>
32
28
  <% end %>
33
29
  </td>
34
30
  </tr>
@@ -11,6 +11,11 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
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
+ # JWT/OIDC per application signing verification
15
+ # t.text :jwt_public_key, null: true
16
+ # t.text :jws_jwk, null: true
17
+ # RP-initiated logout
18
+ # t.string :post_logout_redirect_uri, null: false
14
19
  end
15
20
 
16
21
  create_table :oauth_grants do |t|
@@ -19,6 +24,7 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
19
24
  t.integer :oauth_application_id
20
25
  t.foreign_key :oauth_applications, column: :oauth_application_id
21
26
  t.string :code, null: false
27
+ t.index(%i[oauth_application_id code], unique: true)
22
28
  t.datetime :expires_in, null: false
23
29
  t.string :redirect_uri
24
30
  t.datetime :revoked_at
@@ -31,7 +37,9 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
31
37
  # t.string :code_challenge_method
32
38
  # uncomment to use OIDC nonce
33
39
  # t.string :nonce
34
- t.index(%i[oauth_application_id code], unique: true)
40
+ # device code grant
41
+ # t.string :user_code, null: true, unique: true
42
+ # t.datetime :last_polled_at, null: true
35
43
  end
36
44
 
37
45
  create_table :oauth_tokens do |t|