Class: StandardId::Api::Oauth::IntrospectionsController

Inherits:
BaseController show all
Defined in:
app/controllers/standard_id/api/oauth/introspections_controller.rb

Overview

RFC 7662 OAuth 2.0 Token Introspection (POST /oauth/introspect).

Off by default. The endpoint is fully absent (404) unless StandardId.config.oauth.introspection_enabled is true, mirroring how dynamic_registration_enabled gates /oauth/register: an endpoint that answers questions about other people's tokens is not something to expose by accident.

Confidential clients only (RFC 7662 §2.1 requires the caller be authorized). Credentials arrive as HTTP Basic or in the form body, per RFC 6749 §2.3.1 — never both.

Every failure mode renders {"active": false} with no other members, per RFC 7662 §2.2. That includes bad client credentials, a blank token, a garbage token, a revoked token, and a tripped rate limit. The endpoint deliberately reveals nothing beyond that one bit.

What introspection can and cannot tell you here

Read this before building an authorization gate on it.

Access tokens are stateless: this engine never persists them and they carry no sid, so there is nothing to look up. A revoked session's access token therefore introspects as active: true until its exp. Introspection of an access token answers "was this minted by us, and is it unexpired?" — not "is it still honoured?". The only mitigation is a short access_token_lifetime; a caller who assumes otherwise will build a gate that keeps honouring revoked credentials for a full token lifetime.

Refresh tokens ARE persisted (as SHA256(jti)), so those are checked against the row: a revoked or expired refresh token introspects as inactive, correctly and immediately.

Constant Summary

Constants included from RateLimitHandling

RateLimitHandling::DEFAULT_RETRY_AFTER, RateLimitHandling::RATE_LIMIT_STORE

Instance Method Summary collapse

Methods included from RateLimitHandling

login_per_email, login_per_ip, resolve_login_alias

Methods included from ControllerPolicy

all_controllers, authenticated_controllers, public_controllers, register, registry_snapshot, reset_registry!

Instance Method Details

#createObject

POST /oauth/introspect



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/controllers/standard_id/api/oauth/introspections_controller.rb', line 79

def create
  return render_inactive if authenticate_client!.nil?

  token = params[:token].to_s
  return render_inactive if token.blank?

  payload = decode_token(token)
  return render_inactive if payload.nil?

  # Persisted refresh tokens are checkable; access tokens are not.
  persisted = StandardId::RefreshToken.find_by_jti(payload[:jti].to_s) if payload[:jti].present?
  return render_inactive if persisted && !persisted.active?

  render json: active_response(payload, persisted), status: :ok
end