rodauth-oauth 1.0.0.pre.beta1 → 1.0.0.pre.beta2
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 +6 -5
- data/doc/release_notes/1_0_0_beta2.md +34 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +19 -7
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +54 -43
- data/lib/rodauth/features/oauth_application_management.rb +2 -2
- data/lib/rodauth/features/oauth_authorization_code_grant.rb +31 -6
- data/lib/rodauth/features/oauth_authorize_base.rb +16 -6
- data/lib/rodauth/features/oauth_base.rb +35 -16
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +7 -4
- data/lib/rodauth/features/oauth_implicit_grant.rb +6 -5
- data/lib/rodauth/features/oauth_jwt.rb +3 -3
- data/lib/rodauth/features/oauth_jwt_base.rb +29 -6
- data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +7 -4
- data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +64 -10
- data/lib/rodauth/features/oauth_resource_indicators.rb +0 -4
- data/lib/rodauth/features/oauth_resource_server.rb +3 -3
- data/lib/rodauth/features/oauth_saml_bearer_grant.rb +2 -0
- data/lib/rodauth/features/oidc.rb +231 -183
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +65 -25
- data/lib/rodauth/features/oidc_rp_initiated_logout.rb +115 -0
- data/lib/rodauth/oauth/http_extensions.rb +15 -2
- data/lib/rodauth/oauth/ttl_store.rb +2 -0
- data/lib/rodauth/oauth/version.rb +1 -1
- data/locales/en.yml +3 -1
- data/locales/pt.yml +3 -1
- data/templates/authorize.str +17 -10
- metadata +5 -2
| @@ -51,9 +51,25 @@ module Rodauth | |
| 51 51 | 
             
                    end
         | 
| 52 52 | 
             
                  end
         | 
| 53 53 |  | 
| 54 | 
            +
                  if features.include?(:oauth_jwt_secured_authorization_request)
         | 
| 55 | 
            +
                    if (value = @oauth_application_params[oauth_applications_request_uris_column])
         | 
| 56 | 
            +
                      if value.is_a?(Array)
         | 
| 57 | 
            +
                        @oauth_application_params[oauth_applications_request_uris_column] = value.each do |req_uri|
         | 
| 58 | 
            +
                          unless check_valid_uri?(req_uri)
         | 
| 59 | 
            +
                            register_throw_json_response_error("invalid_redirect_uri", register_invalid_uri_message(req_uri))
         | 
| 60 | 
            +
                          end
         | 
| 61 | 
            +
                        end.join(" ")
         | 
| 62 | 
            +
                      else
         | 
| 63 | 
            +
                        register_throw_json_response_error("invalid_redirect_uri", register_invalid_uri_message(value))
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
                    elsif oauth_require_request_uri_registration
         | 
| 66 | 
            +
                      register_throw_json_response_error("invalid_client_metadata", register_required_param_message("request_uris"))
         | 
| 67 | 
            +
                    end
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 54 70 | 
             
                  if (value = @oauth_application_params[oauth_applications_subject_type_column])
         | 
| 55 71 | 
             
                    unless %w[pairwise public].include?(value)
         | 
| 56 | 
            -
                      register_throw_json_response_error("invalid_client_metadata",  | 
| 72 | 
            +
                      register_throw_json_response_error("invalid_client_metadata", register_invalid_client_metadata_message("subject_type", value))
         | 
| 57 73 | 
             
                    end
         | 
| 58 74 |  | 
| 59 75 | 
             
                    if value == "pairwise"
         | 
| @@ -84,51 +100,75 @@ module Rodauth | |
| 84 100 | 
             
                        register_throw_json_response_error("invalid_client_metadata", register_invalid_param_message("id_token_signed_response_alg"))
         | 
| 85 101 | 
             
                      end
         | 
| 86 102 | 
             
                    elsif !oauth_jwt_jws_algorithms_supported.include?(value)
         | 
| 87 | 
            -
                      register_throw_json_response_error("invalid_client_metadata", | 
| 103 | 
            +
                      register_throw_json_response_error("invalid_client_metadata",
         | 
| 104 | 
            +
                                                         register_invalid_client_metadata_message("id_token_signed_response_alg", value))
         | 
| 88 105 | 
             
                    end
         | 
| 89 106 | 
             
                  end
         | 
| 90 107 |  | 
| 91 | 
            -
                  if ( | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 108 | 
            +
                  if features.include?(:oauth_jwt_secured_authorization_request)
         | 
| 109 | 
            +
                    if defined?(oauth_applications_request_object_signing_alg_column) &&
         | 
| 110 | 
            +
                       (value = @oauth_application_params[oauth_applications_request_object_signing_alg_column]) &&
         | 
| 111 | 
            +
                       !oauth_jwt_jws_algorithms_supported.include?(value) && !(value == "none" && oauth_request_object_signing_alg_allow_none)
         | 
| 112 | 
            +
                      register_throw_json_response_error("invalid_client_metadata",
         | 
| 113 | 
            +
                                                         register_invalid_client_metadata_message("request_object_signing_alg", value))
         | 
| 114 | 
            +
                    end
         | 
| 95 115 |  | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 116 | 
            +
                    if defined?(oauth_applications_request_object_encryption_alg_column) &&
         | 
| 117 | 
            +
                       (value = @oauth_application_params[oauth_applications_request_object_encryption_alg_column]) &&
         | 
| 118 | 
            +
                       !oauth_jwt_jwe_algorithms_supported.include?(value)
         | 
| 119 | 
            +
                      register_throw_json_response_error("invalid_client_metadata",
         | 
| 120 | 
            +
                                                         register_invalid_client_metadata_message("request_object_encryption_alg", value))
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                    if defined?(oauth_applications_request_object_encryption_enc_column) &&
         | 
| 124 | 
            +
                       (value = @oauth_application_params[oauth_applications_request_object_encryption_enc_column]) &&
         | 
| 125 | 
            +
                       !oauth_jwt_jwe_encryption_methods_supported.include?(value)
         | 
| 126 | 
            +
                      register_throw_json_response_error("invalid_client_metadata",
         | 
| 127 | 
            +
                                                         register_invalid_client_metadata_message("request_object_encryption_enc", value))
         | 
| 128 | 
            +
                    end
         | 
| 99 129 | 
             
                  end
         | 
| 100 130 |  | 
| 101 | 
            -
                  if ( | 
| 102 | 
            -
             | 
| 103 | 
            -
                     | 
| 131 | 
            +
                  if features.include?(:oidc_rp_initiated_logout) && (defined?(oauth_applications_post_logout_redirect_uris_column) &&
         | 
| 132 | 
            +
                       (value = @oauth_application_params[oauth_applications_post_logout_redirect_uris_column]))
         | 
| 133 | 
            +
                    if value.is_a?(Array)
         | 
| 134 | 
            +
                      @oauth_application_params[oauth_applications_post_logout_redirect_uris_column] = value.each do |redirect_uri|
         | 
| 135 | 
            +
                        unless check_valid_uri?(redirect_uri)
         | 
| 136 | 
            +
                          register_throw_json_response_error("invalid_client_metadata", register_invalid_uri_message(redirect_uri))
         | 
| 137 | 
            +
                        end
         | 
| 138 | 
            +
                      end.join(" ")
         | 
| 139 | 
            +
                    else
         | 
| 140 | 
            +
                      register_throw_json_response_error("invalid_client_metadata", register_invalid_uri_message(value))
         | 
| 141 | 
            +
                    end
         | 
| 104 142 | 
             
                  end
         | 
| 105 143 |  | 
| 106 | 
            -
                  if (value = @oauth_application_params[ | 
| 144 | 
            +
                  if (value = @oauth_application_params[oauth_applications_id_token_encrypted_response_alg_column]) &&
         | 
| 107 145 | 
             
                     !oauth_jwt_jwe_algorithms_supported.include?(value)
         | 
| 108 | 
            -
                    register_throw_json_response_error("invalid_client_metadata", | 
| 146 | 
            +
                    register_throw_json_response_error("invalid_client_metadata",
         | 
| 147 | 
            +
                                                       register_invalid_client_metadata_message("id_token_encrypted_response_alg", value))
         | 
| 109 148 | 
             
                  end
         | 
| 110 149 |  | 
| 111 | 
            -
                  if (value = @oauth_application_params[ | 
| 150 | 
            +
                  if (value = @oauth_application_params[oauth_applications_id_token_encrypted_response_enc_column]) &&
         | 
| 112 151 | 
             
                     !oauth_jwt_jwe_encryption_methods_supported.include?(value)
         | 
| 113 | 
            -
                    register_throw_json_response_error("invalid_client_metadata", | 
| 152 | 
            +
                    register_throw_json_response_error("invalid_client_metadata",
         | 
| 153 | 
            +
                                                       register_invalid_client_metadata_message("id_token_encrypted_response_enc", value))
         | 
| 114 154 | 
             
                  end
         | 
| 115 155 |  | 
| 116 | 
            -
                  if  | 
| 117 | 
            -
                     (value = @oauth_application_params[oauth_applications_request_object_signing_alg_column]) &&
         | 
| 156 | 
            +
                  if (value = @oauth_application_params[oauth_applications_userinfo_signed_response_alg_column]) &&
         | 
| 118 157 | 
             
                     !oauth_jwt_jws_algorithms_supported.include?(value)
         | 
| 119 | 
            -
                    register_throw_json_response_error("invalid_client_metadata", | 
| 158 | 
            +
                    register_throw_json_response_error("invalid_client_metadata",
         | 
| 159 | 
            +
                                                       register_invalid_client_metadata_message("userinfo_signed_response_alg", value))
         | 
| 120 160 | 
             
                  end
         | 
| 121 161 |  | 
| 122 | 
            -
                  if  | 
| 123 | 
            -
                     (value = @oauth_application_params[oauth_applications_request_object_encryption_alg_column]) &&
         | 
| 162 | 
            +
                  if (value = @oauth_application_params[oauth_applications_userinfo_encrypted_response_alg_column]) &&
         | 
| 124 163 | 
             
                     !oauth_jwt_jwe_algorithms_supported.include?(value)
         | 
| 125 | 
            -
                    register_throw_json_response_error("invalid_client_metadata", | 
| 164 | 
            +
                    register_throw_json_response_error("invalid_client_metadata",
         | 
| 165 | 
            +
                                                       register_invalid_client_metadata_message("userinfo_encrypted_response_alg", value))
         | 
| 126 166 | 
             
                  end
         | 
| 127 167 |  | 
| 128 | 
            -
                  if  | 
| 129 | 
            -
                     (value = @oauth_application_params[oauth_applications_request_object_encryption_enc_column]) &&
         | 
| 168 | 
            +
                  if (value = @oauth_application_params[oauth_applications_userinfo_encrypted_response_enc_column]) &&
         | 
| 130 169 | 
             
                     !oauth_jwt_jwe_encryption_methods_supported.include?(value)
         | 
| 131 | 
            -
                    register_throw_json_response_error("invalid_client_metadata", | 
| 170 | 
            +
                    register_throw_json_response_error("invalid_client_metadata",
         | 
| 171 | 
            +
                                                       register_invalid_client_metadata_message("userinfo_encrypted_response_enc", value))
         | 
| 132 172 | 
             
                  end
         | 
| 133 173 | 
             
                end
         | 
| 134 174 |  | 
| @@ -0,0 +1,115 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "rodauth/oauth"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Rodauth
         | 
| 6 | 
            +
              Feature.define(:oidc_rp_initiated_logout, :OidcRpInitiatedLogout) do
         | 
| 7 | 
            +
                depends :oidc
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                auth_value_method :oauth_applications_post_logout_redirect_uris_column, :post_logout_redirect_uris
         | 
| 10 | 
            +
                translatable_method :oauth_invalid_post_logout_redirect_uri_message, "Invalid post logout redirect URI"
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # /oidc-logout
         | 
| 13 | 
            +
                auth_server_route(:oidc_logout) do |r|
         | 
| 14 | 
            +
                  require_authorizable_account
         | 
| 15 | 
            +
                  before_oidc_logout_route
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # OpenID Providers MUST support the use of the HTTP GET and POST methods
         | 
| 18 | 
            +
                  r.on method: %i[get post] do
         | 
| 19 | 
            +
                    catch_error do
         | 
| 20 | 
            +
                      validate_oidc_logout_params
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      #
         | 
| 23 | 
            +
                      # why this is done:
         | 
| 24 | 
            +
                      #
         | 
| 25 | 
            +
                      # we need to decode the id token in order to get the application, because, if the
         | 
| 26 | 
            +
                      # signing key is application-specific, we don't know how to verify the signature
         | 
| 27 | 
            +
                      # beforehand. Hence, we have to do it twice: decode-and-do-not-verify, initialize
         | 
| 28 | 
            +
                      # the @oauth_application, and then decode-and-verify.
         | 
| 29 | 
            +
                      #
         | 
| 30 | 
            +
                      claims = jwt_decode(param("id_token_hint"), verify_claims: false)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                      redirect_logout_with_error(oauth_invalid_client_message) unless claims
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                      oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["aud"]).first
         | 
| 35 | 
            +
                      oauth_grant = db[oauth_grants_table]
         | 
| 36 | 
            +
                                    .where(
         | 
| 37 | 
            +
                                      oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
         | 
| 38 | 
            +
                                      oauth_grants_account_id_column => account_id
         | 
| 39 | 
            +
                                    ).first
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                      # check whether ID token belongs to currently logged-in user
         | 
| 42 | 
            +
                      redirect_logout_with_error(oauth_invalid_client_message) unless oauth_grant && claims["sub"] == jwt_subject(oauth_grant,
         | 
| 43 | 
            +
                                                                                                                                  oauth_application)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      # When an id_token_hint parameter is present, the OP MUST validate that it was the issuer of the ID Token.
         | 
| 46 | 
            +
                      redirect_logout_with_error(oauth_invalid_client_message) unless claims && claims["iss"] == oauth_jwt_issuer
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                      # now let's logout from IdP
         | 
| 49 | 
            +
                      transaction do
         | 
| 50 | 
            +
                        before_logout
         | 
| 51 | 
            +
                        logout
         | 
| 52 | 
            +
                        after_logout
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                      error_message = logout_notice_flash
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                      if (post_logout_redirect_uri = param_or_nil("post_logout_redirect_uri"))
         | 
| 58 | 
            +
                        error_message = catch(:default_logout_redirect) do
         | 
| 59 | 
            +
                          oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["client_id"]).first
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                          throw(:default_logout_redirect, oauth_invalid_client_message) unless oauth_application
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                          post_logout_redirect_uris = oauth_application[oauth_applications_post_logout_redirect_uris_column].split(" ")
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                          unless post_logout_redirect_uris.include?(post_logout_redirect_uri)
         | 
| 66 | 
            +
                            throw(:default_logout_redirect,
         | 
| 67 | 
            +
                                  oauth_invalid_post_logout_redirect_uri_message)
         | 
| 68 | 
            +
                          end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                          if (state = param_or_nil("state"))
         | 
| 71 | 
            +
                            post_logout_redirect_uri = URI(post_logout_redirect_uri)
         | 
| 72 | 
            +
                            params = ["state=#{CGI.escape(state)}"]
         | 
| 73 | 
            +
                            params << post_logout_redirect_uri.query if post_logout_redirect_uri.query
         | 
| 74 | 
            +
                            post_logout_redirect_uri.query = params.join("&")
         | 
| 75 | 
            +
                            post_logout_redirect_uri = post_logout_redirect_uri.to_s
         | 
| 76 | 
            +
                          end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                          redirect(post_logout_redirect_uri)
         | 
| 79 | 
            +
                        end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                      end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                      redirect_logout_with_error(error_message)
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    redirect_response_error("invalid_request")
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                private
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                # Logout
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def validate_oidc_logout_params
         | 
| 95 | 
            +
                  redirect_logout_with_error(oauth_invalid_client_message) unless param_or_nil("id_token_hint")
         | 
| 96 | 
            +
                  # check if valid token hint type
         | 
| 97 | 
            +
                  return unless (redirect_uri = param_or_nil("post_logout_redirect_uri"))
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  return if check_valid_no_fragment_uri?(redirect_uri)
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                  redirect_logout_with_error(oauth_invalid_client_message)
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                def redirect_logout_with_error(error_message = oauth_invalid_client_message)
         | 
| 105 | 
            +
                  set_notice_flash(error_message)
         | 
| 106 | 
            +
                  redirect(logout_redirect)
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                def oauth_server_metadata_body(*)
         | 
| 110 | 
            +
                  super.tap do |data|
         | 
| 111 | 
            +
                    data[:end_session_endpoint] = oidc_logout_url
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
            end
         | 
| @@ -16,6 +16,9 @@ module Rodauth | |
| 16 16 |  | 
| 17 17 | 
             
                    http = Net::HTTP.new(uri.host, uri.port)
         | 
| 18 18 | 
             
                    http.use_ssl = uri.scheme == "https"
         | 
| 19 | 
            +
                    http.open_timeout = 15
         | 
| 20 | 
            +
                    http.read_timeout = 15
         | 
| 21 | 
            +
                    http.write_timeout = 15 if http.respond_to?(:write_timeout)
         | 
| 19 22 |  | 
| 20 23 | 
             
                    if form_data
         | 
| 21 24 | 
             
                      request = Net::HTTP::Post.new(uri.request_uri)
         | 
| @@ -44,9 +47,19 @@ module Rodauth | |
| 44 47 | 
             
                      response = http_request(uri, *args)
         | 
| 45 48 | 
             
                      ttl = if response.key?("cache-control")
         | 
| 46 49 | 
             
                              cache_control = response["cache-control"]
         | 
| 47 | 
            -
                              cache_control | 
| 50 | 
            +
                              if cache_control.include?("no-cache")
         | 
| 51 | 
            +
                                nil
         | 
| 52 | 
            +
                              else
         | 
| 53 | 
            +
                                max_age = cache_control[/max-age=(\d+)/, 1].to_i
         | 
| 54 | 
            +
                                max_age.zero? ? nil : max_age
         | 
| 55 | 
            +
                              end
         | 
| 48 56 | 
             
                            elsif response.key?("expires")
         | 
| 49 | 
            -
                               | 
| 57 | 
            +
                              expires = response["expires"]
         | 
| 58 | 
            +
                              begin
         | 
| 59 | 
            +
                                Time.parse(expires).to_i - Time.now.to_i
         | 
| 60 | 
            +
                              rescue ArgumentError
         | 
| 61 | 
            +
                                nil
         | 
| 62 | 
            +
                              end
         | 
| 50 63 | 
             
                            end
         | 
| 51 64 |  | 
| 52 65 | 
             
                      [JSON.parse(response.body, symbolize_names: true), ttl]
         | 
| @@ -28,6 +28,8 @@ class Rodauth::OAuth::TtlStore | |
| 28 28 |  | 
| 29 29 | 
             
                payload, ttl = block.call
         | 
| 30 30 |  | 
| 31 | 
            +
                return payload unless ttl
         | 
| 32 | 
            +
             | 
| 31 33 | 
             
                @store_mutex.synchronize do
         | 
| 32 34 | 
             
                  # given that the block call triggers network, and two requests for the same key be processed
         | 
| 33 35 | 
             
                  # at the same time, this ensures the first one wins.
         | 
    
        data/locales/en.yml
    CHANGED
    
    | @@ -55,6 +55,7 @@ en: | |
| 55 55 | 
             
                invalid_url_message: "Invalid URL"
         | 
| 56 56 | 
             
                oauth_unsupported_token_type_message: "Invalid token type hint"
         | 
| 57 57 | 
             
                null_error_message: "is not filled"
         | 
| 58 | 
            +
                oauth_unsupported_response_type_message: "Unsupported response type"
         | 
| 58 59 | 
             
                oauth_already_in_use_message: "error generating unique token"
         | 
| 59 60 | 
             
                oauth_expired_token_message: "the device code has expired"
         | 
| 60 61 | 
             
                oauth_access_denied_message: "the authorization request has been denied"
         | 
| @@ -62,6 +63,7 @@ en: | |
| 62 63 | 
             
                oauth_slow_down_message: "authorization request is still pending but poll interval should be increased"
         | 
| 63 64 | 
             
                oauth_code_challenge_required_message: "code challenge required"
         | 
| 64 65 | 
             
                oauth_unsupported_transform_algorithm_message: "transform algorithm not supported"
         | 
| 65 | 
            -
                oauth_request_uri_not_supported_message: "request uri is unsupported"
         | 
| 66 66 | 
             
                oauth_invalid_request_object_message: "request object is invalid"
         | 
| 67 67 | 
             
                oauth_invalid_scope_message: "The Access Token expired"
         | 
| 68 | 
            +
                oauth_authorize_parameter_required: "'%{parameter}' is a required parameter"
         | 
| 69 | 
            +
                oauth_invalid_post_logout_redirect_uri_message: "Invalid post logout redirect URI"
         | 
    
        data/locales/pt.yml
    CHANGED
    
    | @@ -55,6 +55,7 @@ pt: | |
| 55 55 | 
             
                invalid_url_message: "URL inválido"
         | 
| 56 56 | 
             
                oauth_unsupported_token_type_message: "Sugestão de tipo de token inválida"
         | 
| 57 57 | 
             
                null_error_message: "não está preenchido"
         | 
| 58 | 
            +
                oauth_unsupported_response_type_message: "Tipo de resposta inválido"
         | 
| 58 59 | 
             
                oauth_already_in_use_message: "erro ao gerar token único"
         | 
| 59 60 | 
             
                oauth_expired_token_message: "o código de dispositivo expirou"
         | 
| 60 61 | 
             
                oauth_access_denied_message: "o pedido de autorização foi negado"
         | 
| @@ -62,6 +63,7 @@ pt: | |
| 62 63 | 
             
                oauth_slow_down_message: "o pedido de autorização ainda está pendente mas o intervalo de actualização deve ser aumentado"
         | 
| 63 64 | 
             
                oauth_code_challenge_required_message: "código de negociação necessário"
         | 
| 64 65 | 
             
                oauth_unsupported_transform_algorithm_message: "algoritmo de transformação não suportado"
         | 
| 65 | 
            -
                oauth_request_uri_not_supported_message: "request_uri não é suportado"
         | 
| 66 66 | 
             
                oauth_invalid_request_object_message: "request_object é inválido"
         | 
| 67 67 | 
             
                oauth_invalid_scope_message: "O Token de acesso expirou"
         | 
| 68 | 
            +
                oauth_authorize_parameter_required: "'%{parameter}' é um parâmetro obrigatório"
         | 
| 69 | 
            +
                oauth_invalid_post_logout_redirect_uri_message: "URI de redireccionamento pós-logout inválido"
         | 
    
        data/templates/authorize.str
    CHANGED
    
    | @@ -9,12 +9,13 @@ | |
| 9 9 | 
             
              }
         | 
| 10 10 | 
             
              <p class="lead">
         | 
| 11 11 | 
             
              #{
         | 
| 12 | 
            -
                rodauth. | 
| 13 | 
            -
             | 
| 12 | 
            +
                application_uri = rodauth.oauth_application[rodauth.oauth_applications_homepage_url_column]
         | 
| 13 | 
            +
                application_name = application_uri ? (<<-LINK) : rodauth.oauth_application[rodauth.oauth_applications_name_column]
         | 
| 14 | 
            +
                  <a target="_blank" href="#{h(application_uri)}">
         | 
| 14 15 | 
             
                    #{h(rodauth.oauth_application[rodauth.oauth_applications_name_column])}
         | 
| 15 16 | 
             
                  </a>
         | 
| 16 17 | 
             
                LINK
         | 
| 17 | 
            -
                )
         | 
| 18 | 
            +
                rodauth.authorize_page_lead(name: application_name)
         | 
| 18 19 | 
             
              }
         | 
| 19 20 | 
             
              </p>
         | 
| 20 21 | 
             
              <div class="list-group">
         | 
| @@ -60,12 +61,16 @@ | |
| 60 61 |  | 
| 61 62 | 
             
                #{
         | 
| 62 63 | 
             
                  rodauth.authorize_scopes.map do |scope|
         | 
| 63 | 
            -
                     | 
| 64 | 
            -
                      < | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 64 | 
            +
                    if rodauth.features.include?(:oidc) && scope == "offline_access"
         | 
| 65 | 
            +
                      "<input type=\"hidden\" name=\"scope[]\" value=\"#{scope}\" />"
         | 
| 66 | 
            +
                    else
         | 
| 67 | 
            +
                      <<-HTML
         | 
| 68 | 
            +
                        <div class="form-check">
         | 
| 69 | 
            +
                          <input id="#{scope}" class="form-check-input" type="checkbox" name="scope[]" value="#{h(scope)}">
         | 
| 70 | 
            +
                          <label class="form-check-label" for="#{scope}">#{h(scope)}</label>
         | 
| 71 | 
            +
                        </div>
         | 
| 72 | 
            +
                      HTML
         | 
| 73 | 
            +
                    end
         | 
| 69 74 | 
             
                  end.join
         | 
| 70 75 | 
             
                }
         | 
| 71 76 |  | 
| @@ -77,10 +82,12 @@ | |
| 77 82 | 
             
                #{"<input type=\"hidden\" name=\"redirect_uri\" value=\"#{rodauth.redirect_uri}\"/>" if rodauth.param_or_nil("redirect_uri")}
         | 
| 78 83 | 
             
                #{"<input type=\"hidden\" name=\"code_challenge\" value=\"#{rodauth.param("code_challenge")}\"/>" if rodauth.features.include?(:oauth_pkce) && rodauth.param_or_nil("code_challenge")}
         | 
| 79 84 | 
             
                #{"<input type=\"hidden\" name=\"code_challenge_method\" value=\"#{rodauth.param("code_challenge_method")}\"/>" if rodauth.features.include?(:oauth_pkce) && rodauth.param_or_nil("code_challenge_method")}
         | 
| 85 | 
            +
                #{"<input type=\"hidden\" name=\"prompt\" value=\"#{rodauth.param("prompt")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("prompt")}
         | 
| 80 86 | 
             
                #{"<input type=\"hidden\" name=\"nonce\" value=\"#{rodauth.param("nonce")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("nonce")}
         | 
| 81 87 | 
             
                #{"<input type=\"hidden\" name=\"ui_locales\" value=\"#{rodauth.param("ui_locales")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("ui_locales")}
         | 
| 82 88 | 
             
                #{"<input type=\"hidden\" name=\"claims_locales\" value=\"#{rodauth.param("claims_locales")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("claims_locales")}
         | 
| 83 | 
            -
                #{"<input type=\"hidden\" name=\" | 
| 89 | 
            +
                #{"<input type=\"hidden\" name=\"claims\" value=\"#{h(rodauth.param("claims"))}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("claims")}
         | 
| 90 | 
            +
                #{"<input type=\"hidden\" name=\"acr_values\" value=\"#{rodauth.param("acr_values")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("acr_values")}
         | 
| 84 91 | 
             
                #{
         | 
| 85 92 | 
             
                  if rodauth.features.include?(:oauth_resource_indicators) && rodauth.resource_indicators
         | 
| 86 93 | 
             
                    rodauth.resource_indicators.map do |resource|
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rodauth-oauth
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.0.0.pre. | 
| 4 | 
            +
              version: 1.0.0.pre.beta2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Tiago Cardoso
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-11-09 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rodauth
         | 
| @@ -67,6 +67,7 @@ extra_rdoc_files: | |
| 67 67 | 
             
            - doc/release_notes/0_9_2.md
         | 
| 68 68 | 
             
            - doc/release_notes/0_9_3.md
         | 
| 69 69 | 
             
            - doc/release_notes/1_0_0_beta1.md
         | 
| 70 | 
            +
            - doc/release_notes/1_0_0_beta2.md
         | 
| 70 71 | 
             
            files:
         | 
| 71 72 | 
             
            - CHANGELOG.md
         | 
| 72 73 | 
             
            - LICENSE.txt
         | 
| @@ -105,6 +106,7 @@ files: | |
| 105 106 | 
             
            - doc/release_notes/0_9_2.md
         | 
| 106 107 | 
             
            - doc/release_notes/0_9_3.md
         | 
| 107 108 | 
             
            - doc/release_notes/1_0_0_beta1.md
         | 
| 109 | 
            +
            - doc/release_notes/1_0_0_beta2.md
         | 
| 108 110 | 
             
            - lib/generators/rodauth/oauth/install_generator.rb
         | 
| 109 111 | 
             
            - lib/generators/rodauth/oauth/templates/app/models/oauth_application.rb
         | 
| 110 112 | 
             
            - lib/generators/rodauth/oauth/templates/app/models/oauth_grant.rb
         | 
| @@ -142,6 +144,7 @@ files: | |
| 142 144 | 
             
            - lib/rodauth/features/oauth_token_revocation.rb
         | 
| 143 145 | 
             
            - lib/rodauth/features/oidc.rb
         | 
| 144 146 | 
             
            - lib/rodauth/features/oidc_dynamic_client_registration.rb
         | 
| 147 | 
            +
            - lib/rodauth/features/oidc_rp_initiated_logout.rb
         | 
| 145 148 | 
             
            - lib/rodauth/oauth.rb
         | 
| 146 149 | 
             
            - lib/rodauth/oauth/database_extensions.rb
         | 
| 147 150 | 
             
            - lib/rodauth/oauth/http_extensions.rb
         |