diff options
| author | mo khan <mo@mokhan.ca> | 2025-03-17 21:38:32 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-03-17 21:38:32 -0600 |
| commit | a255f9818c4fab5c2e1c3e9ded61d37991b2cebb (patch) | |
| tree | 91fb5be83ec57fdddb6515d69de01fec36f078ea /bin | |
| parent | 66edae4510b51570e6e4a21ef38dfc7defb63982 (diff) | |
feat: add a token introspection endpoint
Diffstat (limited to 'bin')
| -rwxr-xr-x | bin/idp | 47 |
1 files changed, 35 insertions, 12 deletions
@@ -105,7 +105,7 @@ module Authn end def create_access_token - ::Authz::JWT.new(sub: to_global_id.to_s, iat: Time.now.to_i) + ::Authz::JWT.new(sub: to_global_id.to_s) end def assertion_attributes_for(request) @@ -323,10 +323,30 @@ module Authz end class JWT + class << self + # TODO:: validate signature + def decode(encoded) + _header, body, _signature = encoded + .split('.', 3) + .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) rescue {} } + new(body) + end + end + attr_reader :claims def initialize(claims) - @claims = claims + now = Time.now.to_i + @claims = { + iat: now, + nbf: now, + jti: SecureRandom.uuid, + }.merge(claims) + end + + def active? + # TODO:: check if current time is within valid range + true end def to_jwt @@ -360,21 +380,14 @@ module Authz false end - def subject_of(token) - _header, claims, _signature = from_jwt(token) - claims[:sub] + def subject_of(encoded_token) + token = ::Authz::JWT.decode(encoded_token) + token&.claims[:sub] end def resource_from(global_id) GlobalID::Locator.locate(global_id) end - - # TODO:: validate signature - def from_jwt(token) - token - .split('.', 3) - .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) rescue {} } - end end end @@ -499,6 +512,9 @@ module Authz case request.path when "/oauth/authorize" # RFC-6749 return post_authorize(request) + when "/oauth/introspect" # RFC-7662 + params = request.content_type == "application/json" ? JSON.parse(request.body.read, symbolize_names: true) : Hash[URI.decode_www_form(request.body.read)].transform_keys(&:to_sym) + return post_introspect(params.slice(:token, :token_type_hint)) when "/oauth/token" # RFC-6749 params = request.content_type == "application/json" ? JSON.parse(request.body.read, symbolize_names: true) : Hash[URI.decode_www_form(request.body.read)].transform_keys(&:to_sym) grant = AuthorizationGrant.find_by(params) @@ -515,6 +531,13 @@ module Authz http_not_found end + private + + def post_introspect(params) + token = ::Authz::JWT.decode(params[:token]) + return [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate(token.claims.merge(active: token.active?))]] + end + def get_authorize(oauth_params) template = <<~ERB <!DOCTYPE html> |
