Module: StandardId::AudienceVerification

Extended by:
ActiveSupport::Concern
Defined in:
app/controllers/concerns/standard_id/audience_verification.rb

Overview

Per-controller audience verification for API endpoints.

StandardId enforces audience in three layers:

1. At encode time (`Oauth::TokenGrantFlow#validate_audience!`):
   rejects issuance of tokens with an audience outside the global
   `StandardId.config.oauth.allowed_audiences` list.
2. At decode time (`JwtService.decode(..., allowed_audiences:)`):
   rejects tokens whose `aud` claim does not match the caller-supplied
   list, raising `StandardId::InvalidAudienceError`. The engine's
   `Api::TokenManager#verify_jwt_token` wires this automatically when
   `StandardId.config.oauth.allowed_audiences` is non-empty — a
   mismatch there is normalised to the same 401 "invalid token"
   response as a bad signature. Call sites that pass no arguments
   to `decode` directly still skip aud checks by design.
3. At the controller, via this concern: layers on top as
   per-endpoint defense-in-depth. Required when a controller serves
   a strict subset of the global allowed audiences (e.g., the global
   list is `%w[web api admin]` but `AdminController` must only
   accept `admin`).

With the global decode-time check now automatic, this concern is primarily useful for tightening the allowed audience per controller, not for plugging the “controller forgot to verify aud” gap (which is closed globally when ‘config.oauth.allowed_audiences` is set).

In addition, when ‘StandardId.config.oauth.audience_profile_types` is set, this concern enforces the audience → profile-type binding: after the allowed-audience check, it resolves the current account’s profile for the matched audience and rejects requests whose profile type does not match.

Requires StandardId::ApiAuthentication to be included before this concern (provides ‘verify_access_token!` and `current_session`). An error is raised at include time if ApiAuthentication is missing.

The caller is responsible for registering ‘before_action :verify_access_token!` (typically via ApiAuthentication or a base controller). This concern only adds the `verify_audience!` callback, which must run after token verification so that `current_session` is populated. This is consistent with how `require_scopes!` works in ApiAuthentication.

Examples:

Single audience

class AdminController < Api::BaseController
  include StandardId::AudienceVerification
  verify_audience "admin"
end

Multiple audiences

class SharedController < Api::BaseController
  include StandardId::AudienceVerification
  verify_audience "admin", "mobile"
end