lib/rodauth/features/oauth.rb in rodauth-oauth-0.0.4 vs lib/rodauth/features/oauth.rb in rodauth-oauth-0.0.5
- old
+ new
@@ -1,12 +1,17 @@
# frozen-string-literal: true
require "base64"
+require "securerandom"
+require "net/http"
+require "rodauth/oauth/ttl_store"
+
module Rodauth
Feature.define(:oauth) do
# RUBY EXTENSIONS
+ # :nocov:
unless Regexp.method_defined?(:match?)
module RegexpExtensions
refine(Regexp) do
def match?(*args)
!match(*args).nil?
@@ -30,10 +35,11 @@
end
end
end
using(SuffixExtensions)
end
+ # :nocov:
SCOPES = %w[profile.read].freeze
before "authorize"
after "authorize"
@@ -63,40 +69,34 @@
view "new_oauth_application", "New Oauth Application", "new_oauth_application"
view "oauth_tokens", "Oauth Tokens", "oauth_tokens"
auth_value_method :json_response_content_type, "application/json"
- auth_value_method :oauth_grant_expires_in, 60 * 5 # 60 minutes
+ auth_value_method :oauth_grant_expires_in, 60 * 5 # 5 minutes
auth_value_method :oauth_token_expires_in, 60 * 60 # 60 minutes
auth_value_method :use_oauth_implicit_grant_type?, false
auth_value_method :use_oauth_pkce?, true
auth_value_method :use_oauth_access_type?, true
auth_value_method :oauth_require_pkce, false
auth_value_method :oauth_pkce_challenge_method, "S256"
auth_value_method :oauth_valid_uri_schemes, %w[http https]
- # URL PARAMS
+ auth_value_method :oauth_scope_separator, " "
- # Authorize / token
- %w[
- grant_type code refresh_token client_id client_secret scope
- state redirect_uri scopes token_type_hint token
- access_type approval_prompt response_type
- code_challenge code_challenge_method code_verifier
- ].each do |param|
- auth_value_method :"#{param}_param", param
- end
-
# Application
APPLICATION_REQUIRED_PARAMS = %w[name description scopes homepage_url redirect_uri client_secret].freeze
auth_value_method :oauth_application_required_params, APPLICATION_REQUIRED_PARAMS
(APPLICATION_REQUIRED_PARAMS + %w[client_id]).each do |param|
auth_value_method :"oauth_application_#{param}_param", param
+ translatable_method :"#{param}_label", param.gsub("_", " ").capitalize
end
+ button "Register", "oauth_application"
+ button "Authorize", "oauth_authorize"
+ button "Revoke", "oauth_token_revoke"
# OAuth Token
auth_value_method :oauth_tokens_path, "oauth-tokens"
auth_value_method :oauth_tokens_table, :oauth_tokens
auth_value_method :oauth_tokens_id_column, :id
@@ -171,15 +171,22 @@
auth_value_method :oauth_metadata_service_documentation, nil
auth_value_method :oauth_metadata_ui_locales_supported, nil
auth_value_method :oauth_metadata_op_policy_uri, nil
auth_value_method :oauth_metadata_op_tos_uri, nil
+ # Resource Server params
+ # Only required to use if the plugin is to be used in a resource server
+ auth_value_method :is_authorization_server?, true
+
auth_value_methods(
:fetch_access_token,
:oauth_unique_id_generator,
:secret_matches?,
- :secret_hash
+ :secret_hash,
+ :generate_token_hash,
+ :authorization_server_url,
+ :before_introspection_request
)
auth_value_methods(:only_json?)
redirect(:oauth_application) do |id|
@@ -196,10 +203,12 @@
end
end
auth_value_method :json_request_regexp, %r{\bapplication/(?:vnd\.api\+)?json\b}i
+ SERVER_METADATA = OAuth::TtlStore.new
+
def check_csrf?
case request.path
when oauth_token_path, oauth_introspect_path
false
when oauth_revoke_path
@@ -221,55 +230,58 @@
(accept = request.env["HTTP_ACCEPT"]) && accept =~ json_request_regexp
end
unless method_defined?(:json_request?)
+ # :nocov:
# copied from the jwt feature
def json_request?
return @json_request if defined?(@json_request)
@json_request = request.content_type =~ json_request_regexp
end
+ # :nocov:
end
def initialize(scope)
@scope = scope
end
def state
- param_or_nil(state_param)
+ param_or_nil("state")
end
def scopes
- (param_or_nil(scopes_param) || oauth_application_default_scope).split(" ")
+ (param_or_nil("scope") || oauth_application_default_scope).split(" ")
end
def client_id
- param_or_nil(client_id_param)
+ param_or_nil("client_id")
end
- def client_secret
- param_or_nil(client_secret_param)
- end
-
def redirect_uri
- param_or_nil(redirect_uri_param) || oauth_application[oauth_applications_redirect_uri_column]
+ param_or_nil("redirect_uri") || begin
+ return unless oauth_application
+
+ redirect_uris = oauth_application[oauth_applications_redirect_uri_column].split(" ")
+ redirect_uris.size == 1 ? redirect_uris.first : nil
+ end
end
def token_type_hint
- param_or_nil(token_type_hint_param) || "access_token"
+ param_or_nil("token_type_hint") || "access_token"
end
def token
- param_or_nil(token_param)
+ param_or_nil("token")
end
def oauth_application
return @oauth_application if defined?(@oauth_application)
@oauth_application = begin
- client_id = param(client_id_param)
+ client_id = param_or_nil("client_id")
return unless client_id
db[oauth_applications_table].filter(oauth_applications_client_id_column => client_id).first
end
@@ -289,22 +301,41 @@
def authorization_token
return @authorization_token if defined?(@authorization_token)
# check if there is a token
+ bearer_token = fetch_access_token
+
+ return unless bearer_token
+
# check if token has not expired
# check if token has been revoked
- @authorization_token = oauth_token_by_token(fetch_access_token)
+ @authorization_token = oauth_token_by_token(bearer_token)
end
def require_oauth_authorization(*scopes)
- authorization_required unless authorization_token
+ token_scopes = if is_authorization_server?
+ authorization_required unless authorization_token
- scopes << oauth_application_default_scope if scopes.empty?
+ scopes << oauth_application_default_scope if scopes.empty?
- token_scopes = authorization_token[oauth_tokens_scopes_column].split(",")
+ authorization_token[oauth_tokens_scopes_column].split(oauth_scope_separator)
+ else
+ bearer_token = fetch_access_token
+ authorization_required unless bearer_token
+
+ scopes << oauth_application_default_scope if scopes.empty?
+
+ # where in resource server, NOT the authorization server.
+ payload = introspection_request("access_token", bearer_token)
+
+ authorization_required unless payload["active"]
+
+ payload["scope"].split(oauth_scope_separator)
+ end
+
authorization_required unless scopes.any? { |scope| token_scopes.include?(scope) }
end
# /oauth-applications routes
def oauth_applications
@@ -312,10 +343,11 @@
require_account
request.get "new" do
new_oauth_application_view
end
+
request.on(oauth_applications_id_pattern) do |id|
oauth_application = db[oauth_applications_table].where(oauth_applications_id_column => id).first
scope.instance_variable_set(:@oauth_application, oauth_application)
request.is do
@@ -364,10 +396,68 @@
end
end
private
+ def authorization_server_url
+ base_url
+ end
+
+ def authorization_server_metadata
+ auth_url = URI(authorization_server_url)
+
+ server_metadata = SERVER_METADATA[auth_url]
+
+ return server_metadata if server_metadata
+
+ SERVER_METADATA.set(auth_url) do
+ http = Net::HTTP.new(auth_url.host, auth_url.port)
+ http.use_ssl = auth_url.scheme == "https"
+
+ request = Net::HTTP::Get.new("/.well-known/oauth-authorization-server")
+ request["accept"] = json_response_content_type
+ response = http.request(request)
+ authorization_required unless response.code.to_i == 200
+
+ # time-to-live
+ ttl = if response.key?("cache-control")
+ cache_control = response["cache_control"]
+ cache_control[/max-age=(\d+)/, 1]
+ elsif response.key?("expires")
+ Time.httpdate(response["expires"]).utc.to_i - Time.now.utc.to_i
+ end
+
+ [JSON.parse(response.body, symbolize_names: true), ttl]
+ end
+ end
+
+ def introspection_request(token_type_hint, token)
+ auth_url = URI(authorization_server_url)
+ http = Net::HTTP.new(auth_url.host, auth_url.port)
+ http.use_ssl = auth_url.scheme == "https"
+
+ request = Net::HTTP::Post.new(oauth_introspect_path)
+ request["content-type"] = json_response_content_type
+ request["accept"] = json_response_content_type
+ request.body = JSON.dump({ "token_type_hint" => token_type_hint, "token" => token })
+
+ before_introspection_request(request)
+ response = http.request(request)
+ authorization_required unless response.code.to_i == 200
+
+ JSON.parse(response.body)
+ end
+
+ def before_introspection_request(request); end
+
+ def template_path(page)
+ path = File.join(File.dirname(__FILE__), "../../../templates", "#{page}.str")
+ return super unless File.exist?(path)
+
+ path
+ end
+
# to be used internally. Same semantics as require account, must:
# fetch an authorization basic header
# parse client id and secret
#
def require_oauth_application
@@ -376,20 +466,20 @@
# client_secret_basic
if (token = ((v = request.env["HTTP_AUTHORIZATION"]) && v[/\A *Basic (.*)\Z/, 1]))
client_id, client_secret = Base64.decode64(token).split(/:/, 2)
else
- client_id = param_or_nil(client_id_param)
- client_secret = param_or_nil(client_secret_param)
+ client_id = param_or_nil("client_id")
+ client_secret = param_or_nil("client_secret")
end
authorization_required unless client_id
@oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => client_id).first
# skip if using pkce
- return if @oauth_application && use_oauth_pkce? && param_or_nil(code_verifier_param)
+ return if @oauth_application && use_oauth_pkce? && param_or_nil("code_verifier")
authorization_required unless @oauth_application && secret_matches?(@oauth_application, client_secret)
end
def secret_matches?(oauth_application, secret)
@@ -411,26 +501,26 @@
def token_from_application?(oauth_token, oauth_application)
oauth_token[oauth_tokens_oauth_application_id_column] == oauth_application[oauth_applications_id_column]
end
unless method_defined?(:password_hash)
+ # :nocov:
# From login_requirements_base feature
if ENV["RACK_ENV"] == "test"
def password_hash_cost
BCrypt::Engine::MIN_COST
end
else
- # :nocov:
def password_hash_cost
BCrypt::Engine::DEFAULT_COST
end
- # :nocov:
end
def password_hash(password)
BCrypt::Password.create(password, cost: password_hash_cost)
end
+ # :nocov:
end
def generate_oauth_token(params = {}, should_generate_refresh_token = true)
create_params = {
oauth_grants_expires_in_column => Time.now + oauth_token_expires_in
@@ -464,11 +554,11 @@
def _generate_oauth_token(params = {})
ds = db[oauth_tokens_table]
begin
if ds.supports_returning?(:insert)
- ds.returning.insert(params)
+ ds.returning.insert(params).first
else
id = ds.insert(params)
ds.where(oauth_tokens_id_column => id).first
end
rescue Sequel::UniqueConstraintViolation
@@ -521,15 +611,25 @@
end
end
def validate_oauth_application_params
oauth_application_params.each do |key, value|
- if key == oauth_application_homepage_url_param ||
- key == oauth_application_redirect_uri_param
+ if key == oauth_application_homepage_url_param
- set_field_error(key, invalid_url_message) unless URI::DEFAULT_PARSER.make_regexp(oauth_valid_uri_schemes).match?(value)
+ set_field_error(key, invalid_url_message) unless check_valid_uri?(value)
+ elsif key == oauth_application_redirect_uri_param
+
+ if value.respond_to?(:each)
+ value.each do |uri|
+ next if uri.empty?
+
+ set_field_error(key, invalid_url_message) unless check_valid_uri?(uri)
+ end
+ else
+ set_field_error(key, invalid_url_message) unless check_valid_uri?(value)
+ end
elsif key == oauth_application_scopes_param
value.each do |scope|
set_field_error(key, invalid_scope_message) unless oauth_application_scopes.include?(scope)
end
@@ -543,41 +643,36 @@
create_params = {
oauth_applications_account_id_column => account_id,
oauth_applications_name_column => oauth_application_params[oauth_application_name_param],
oauth_applications_description_column => oauth_application_params[oauth_application_description_param],
oauth_applications_scopes_column => oauth_application_params[oauth_application_scopes_param],
- oauth_applications_homepage_url_column => oauth_application_params[oauth_application_homepage_url_param],
- oauth_applications_redirect_uri_column => oauth_application_params[oauth_application_redirect_uri_param]
+ oauth_applications_homepage_url_column => oauth_application_params[oauth_application_homepage_url_param]
}
+ redirect_uris = oauth_application_params[oauth_application_redirect_uri_param]
+ redirect_uris = redirect_uris.to_a.reject(&:empty?).join(" ") if redirect_uris.respond_to?(:each)
+ create_params[oauth_applications_redirect_uri_column] = redirect_uris unless redirect_uris.empty?
# set client ID/secret pairs
create_params.merge! \
oauth_applications_client_id_column => oauth_unique_id_generator,
oauth_applications_client_secret_column => \
secret_hash(oauth_application_params[oauth_application_client_secret_param])
create_params[oauth_applications_scopes_column] = if create_params[oauth_applications_scopes_column]
- create_params[oauth_applications_scopes_column].join(",")
+ create_params[oauth_applications_scopes_column].join(oauth_scope_separator)
else
oauth_application_default_scope
end
- ds = db[oauth_applications_table]
-
id = nil
raised = begin
- id = if ds.supports_returning?(:insert)
- ds.returning(oauth_applications_id_column).insert(create_params)
- else
- id = db[oauth_applications_table].insert(create_params)
- db[oauth_applications_table].where(oauth_applications_id_column => id).get(oauth_applications_id_column)
- end
- false
+ id = db[oauth_applications_table].insert(create_params)
+ false
rescue Sequel::ConstraintViolation => e
e
- end
+ end
if raised
field = raised.message[/\.(.*)$/, 1]
case raised
when Sequel::UniqueConstraintViolation
@@ -594,29 +689,31 @@
def before_authorize
require_account
end
def validate_oauth_grant_params
+ redirect_response_error("invalid_request", request.referer || default_redirect) unless oauth_application && check_valid_redirect_uri?
+
unless oauth_application && check_valid_redirect_uri? && check_valid_access_type? &&
check_valid_approval_prompt? && check_valid_response_type?
redirect_response_error("invalid_request")
end
redirect_response_error("invalid_scope") unless check_valid_scopes?
validate_pkce_challenge_params if use_oauth_pkce?
end
def try_approval_prompt
- approval_prompt = param_or_nil(approval_prompt_param)
+ approval_prompt = param_or_nil("approval_prompt")
return unless approval_prompt && approval_prompt == "auto"
return if db[oauth_grants_table].where(
oauth_grants_account_id_column => account_id,
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
oauth_grants_redirect_uri_column => redirect_uri,
- oauth_grants_scopes_column => scopes.join(","),
+ oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
oauth_grants_access_type_column => "online"
).count.zero?
# if there's a previous oauth grant for the params combo, it means that this user has approved before.
@@ -626,27 +723,26 @@
def create_oauth_grant
create_params = {
oauth_grants_account_id_column => account_id,
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
oauth_grants_redirect_uri_column => redirect_uri,
- oauth_grants_code_column => oauth_unique_id_generator,
oauth_grants_expires_in_column => Time.now + oauth_grant_expires_in,
- oauth_grants_scopes_column => scopes.join(",")
+ oauth_grants_scopes_column => scopes.join(oauth_scope_separator)
}
# Access Type flow
if use_oauth_access_type?
- if (access_type = param_or_nil(access_type_param))
+ if (access_type = param_or_nil("access_type"))
create_params[oauth_grants_access_type_column] = access_type
end
end
# PKCE flow
if use_oauth_pkce?
- if (code_challenge = param_or_nil(code_challenge_param))
- code_challenge_method = param_or_nil(code_challenge_method_param)
+ if (code_challenge = param_or_nil("code_challenge"))
+ code_challenge_method = param_or_nil("code_challenge_method")
create_params[oauth_grants_code_challenge_column] = code_challenge
create_params[oauth_grants_code_challenge_method_column] = code_challenge_method
elsif oauth_require_pkce
redirect_response_error("code_challenge_required")
@@ -654,16 +750,14 @@
end
ds = db[oauth_grants_table]
begin
- if ds.supports_returning?(:insert)
- ds.returning(authorize_code_column).insert(create_params)
- else
- id = ds.insert(create_params)
- ds.where(oauth_grants_id_column => id).get(oauth_grants_code_column)
- end
+ authorization_code = oauth_unique_id_generator
+ create_params[oauth_grants_code_column] = authorization_code
+ ds.insert(create_params)
+ authorization_code
rescue Sequel::UniqueConstraintViolation
retry
end
end
@@ -672,27 +766,27 @@
def before_token
require_oauth_application
end
def validate_oauth_token_params
- unless (grant_type = param_or_nil(grant_type_param))
+ unless (grant_type = param_or_nil("grant_type"))
redirect_response_error("invalid_request")
end
case grant_type
when "authorization_code"
- redirect_response_error("invalid_request") unless param_or_nil(code_param)
+ redirect_response_error("invalid_request") unless param_or_nil("code")
when "refresh_token"
- redirect_response_error("invalid_request") unless param_or_nil(refresh_token_param)
+ redirect_response_error("invalid_request") unless param_or_nil("refresh_token")
else
redirect_response_error("invalid_request")
end
end
def create_oauth_token
- case param(grant_type_param)
+ case param("grant_type")
when "authorization_code"
create_oauth_token_from_authorization_code(oauth_application)
when "refresh_token"
create_oauth_token_from_token(oauth_application)
else
@@ -701,12 +795,12 @@
end
def create_oauth_token_from_authorization_code(oauth_application)
# fetch oauth grant
oauth_grant = db[oauth_grants_table].where(
- oauth_grants_code_column => param(code_param),
- oauth_grants_redirect_uri_column => param(redirect_uri_param),
+ oauth_grants_code_column => param("code"),
+ oauth_grants_redirect_uri_column => param("redirect_uri"),
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
oauth_grants_revoked_at_column => nil
).where(Sequel[oauth_grants_expires_in_column] >= Sequel::CURRENT_TIMESTAMP)
.for_update
.first
@@ -714,11 +808,11 @@
redirect_response_error("invalid_grant") unless oauth_grant
# PKCE
if use_oauth_pkce?
if oauth_grant[oauth_grants_code_challenge_column]
- code_verifier = param_or_nil(code_verifier_param)
+ code_verifier = param_or_nil("code_verifier")
redirect_response_error("invalid_request") unless code_verifier && check_valid_grant_challenge?(oauth_grant, code_verifier)
elsif oauth_require_pkce
redirect_response_error("code_challenge_required")
end
@@ -741,11 +835,11 @@
generate_oauth_token(create_params, should_generate_refresh_token)
end
def create_oauth_token_from_token(oauth_application)
# fetch oauth token
- oauth_token = oauth_token_by_refresh_token(param(refresh_token_param))
+ oauth_token = oauth_token_by_refresh_token(param("refresh_token"))
redirect_response_error("invalid_grant") unless oauth_token && token_from_application?(oauth_token, oauth_application)
token = oauth_unique_id_generator
@@ -762,11 +856,11 @@
ds = db[oauth_tokens_table].where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
oauth_token = begin
if ds.supports_returning?(:update)
- ds.returning.update(update_params)
+ ds.returning.update(update_params).first
else
ds.update(update_params)
ds.first
end
rescue Sequel::UniqueConstraintViolation
@@ -785,28 +879,26 @@
# check if valid token hint type
if token_type_hint
redirect_response_error("unsupported_token_type") unless TOKEN_HINT_TYPES.include?(token_type_hint)
end
- redirect_response_error("invalid_request") unless param_or_nil(token_param)
+ redirect_response_error("invalid_request") unless param_or_nil("token")
end
def json_token_introspect_payload(token)
return { active: false } unless token
{
active: true,
- scope: token[oauth_tokens_scopes_column].gsub(",", " "),
+ scope: token[oauth_tokens_scopes_column],
client_id: oauth_application[oauth_applications_client_id_column],
# username
token_type: oauth_token_type
}
end
- def before_introspect
- require_oauth_application
- end
+ def before_introspect; end
# Token revocation
def before_revoke
require_oauth_application
@@ -814,29 +906,36 @@
def validate_oauth_revoke_params
# check if valid token hint type
redirect_response_error("unsupported_token_type") unless TOKEN_HINT_TYPES.include?(token_type_hint)
- redirect_response_error("invalid_request") unless param_or_nil(token_param)
+ redirect_response_error("invalid_request") unless param_or_nil("token")
end
def revoke_oauth_token
oauth_token = case token_type_hint
when "access_token"
oauth_token_by_token(token)
when "refresh_token"
oauth_token_by_refresh_token(token)
end
- redirect_response_error("invalid_request") unless oauth_token && token_from_application?(oauth_token, oauth_application)
+ redirect_response_error("invalid_request") unless oauth_token
+ if oauth_application
+ redirect_response_error("invalid_request") unless token_from_application?(oauth_token, oauth_application)
+ else
+ @oauth_application = db[oauth_applications_table].where(oauth_applications_id_column =>
+ oauth_token[oauth_tokens_oauth_application_id_column]).first
+ end
+
update_params = { oauth_tokens_revoked_at_column => Sequel::CURRENT_TIMESTAMP }
ds = db[oauth_tokens_table].where(oauth_tokens_id_column => oauth_token[oauth_tokens_id_column])
oauth_token = if ds.supports_returning?(:update)
- ds.returning.update(update_params)
+ ds.returning.update(update_params).first
else
ds.update(update_params)
ds.first
end
@@ -852,11 +951,11 @@
# we don't need to do anything here, as we revalidate existing tokens
end
# Response helpers
- def redirect_response_error(error_code, redirect_url = request.referer || default_redirect)
+ def redirect_response_error(error_code, redirect_url = redirect_uri || request.referer || default_redirect)
if accepts_json?
throw_json_response_error(invalid_oauth_response_status, error_code)
else
redirect_url = URI.parse(redirect_url)
query_params = []
@@ -901,17 +1000,19 @@
response.write(json_payload)
request.halt
end
unless method_defined?(:_json_response_body)
+ # :nocov:
def _json_response_body(hash)
if request.respond_to?(:convert_to_json)
request.send(:convert_to_json, hash)
else
JSON.dump(hash)
end
end
+ # :nocov:
end
def authorization_required
if accepts_json?
throw_json_response_error(authorization_required_error_status, "invalid_client")
@@ -919,40 +1020,44 @@
set_redirect_error_flash(require_authorization_error_flash)
redirect(require_authorization_redirect)
end
end
+ def check_valid_uri?(uri)
+ URI::DEFAULT_PARSER.make_regexp(oauth_valid_uri_schemes).match?(uri)
+ end
+
def check_valid_scopes?
return false unless scopes
- (scopes - oauth_application[oauth_applications_scopes_column].split(",")).empty?
+ (scopes - oauth_application[oauth_applications_scopes_column].split(oauth_scope_separator)).empty?
end
def check_valid_redirect_uri?
- redirect_uri == oauth_application[oauth_applications_redirect_uri_column]
+ oauth_application[oauth_applications_redirect_uri_column].split(" ").include?(redirect_uri)
end
ACCESS_TYPES = %w[offline online].freeze
def check_valid_access_type?
return true unless use_oauth_access_type?
- access_type = param_or_nil(access_type_param)
+ access_type = param_or_nil("access_type")
!access_type || ACCESS_TYPES.include?(access_type)
end
APPROVAL_PROMPTS = %w[force auto].freeze
def check_valid_approval_prompt?
return true unless use_oauth_access_type?
- approval_prompt = param_or_nil(approval_prompt_param)
+ approval_prompt = param_or_nil("approval_prompt")
!approval_prompt || APPROVAL_PROMPTS.include?(approval_prompt)
end
def check_valid_response_type?
- response_type = param_or_nil(response_type_param)
+ response_type = param_or_nil("response_type")
return true if response_type.nil? || response_type == "code"
return use_oauth_implicit_grant_type? if response_type == "token"
@@ -960,13 +1065,13 @@
end
# PKCE
def validate_pkce_challenge_params
- if param_or_nil(code_challenge_param)
+ if param_or_nil("code_challenge")
- challenge_method = param_or_nil(code_challenge_method_param)
+ challenge_method = param_or_nil("code_challenge_method")
redirect_response_error("code_challenge_required") unless oauth_pkce_challenge_method == challenge_method
else
return unless oauth_require_pkce
redirect_response_error("code_challenge_required")
@@ -1052,20 +1157,25 @@
r.post do
catch_error do
validate_oauth_introspect_params
- oauth_token = case param(token_type_hint_param)
+ oauth_token = case param("token_type_hint")
when "access_token"
- oauth_token_by_token(param(token_param))
+ oauth_token_by_token(param("token"))
when "refresh_token"
- oauth_token_by_refresh_token(param(token_param))
+ oauth_token_by_refresh_token(param("token"))
else
- oauth_token_by_token(param(token_param)) || oauth_token_by_refresh_token(param(token_param))
+ oauth_token_by_token(param("token")) || oauth_token_by_refresh_token(param("token"))
end
- redirect_response_error("invalid_request") if oauth_token && !token_from_application?(oauth_token, oauth_application)
+ if oauth_application
+ redirect_response_error("invalid_request") if oauth_token && !token_from_application?(oauth_token, oauth_application)
+ elsif oauth_token
+ @oauth_application = db[oauth_applications_table].where(oauth_applications_id_column =>
+ oauth_token[oauth_tokens_oauth_application_id_column]).first
+ end
json_response_success(json_token_introspect_payload(oauth_token))
end
throw_json_response_error(invalid_oauth_response_status, "invalid_request")
@@ -1118,12 +1228,12 @@
code = nil
query_params = []
fragment_params = []
transaction do
- case param(response_type_param)
+ case param("response_type")
when "token"
- redirect_response_error("invalid_request", redirect_uri) unless use_oauth_implicit_grant_type?
+ redirect_response_error("invalid_request") unless use_oauth_implicit_grant_type?
create_params = {
oauth_tokens_account_id_column => account_id,
oauth_tokens_oauth_application_id_column => oauth_application[oauth_applications_id_column],
oauth_tokens_scopes_column => scopes