diaspora/diaspora · error · Rack::OAuth2::Server::Authorize::BadRequest

invalid_request

invalid_request

Error message

invalid_request

What it means

On Diaspora's OpenID Connect token endpoint, JWT-bearer client authentication decodes the client_assertion without verification, reads its iss claim, and runs Api::OpenidConnect::OAuthApplication.find_by(client_id: jwt['iss']). If no registered OAuth application has that client_id, it raises Rack::OAuth2::Server::Authorize::BadRequest with error code invalid_request (HTTP 400) before any signature verification happens.

Source

Thrown at app/controllers/api/openid_connect/token_endpoint_controller.rb:24

      skip_before_action :verify_authenticity_token

      def create
        req = Rack::Request.new(request.env)
        if req["client_assertion_type"] == "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
          handle_jwt_bearer(req)
        end
        self.status, headers, self.response_body = Api::OpenidConnect::TokenEndpoint.new.call(request.env)
        headers.each {|name, value| response.headers[name] = value }
        nil
      end

      private

      def handle_jwt_bearer(req)
        jwt_string = req["client_assertion"]
        jwt = JSON::JWT.decode jwt_string, :skip_verification
        o_auth_app = Api::OpenidConnect::OAuthApplication.find_by(client_id: jwt["iss"])
        raise Rack::OAuth2::Server::Authorize::BadRequest(:invalid_request) unless o_auth_app
        public_key = fetch_public_key(o_auth_app, jwt)
        JSON::JWT.decode(jwt_string, JSON::JWK.new(public_key).to_key)
        req.update_param("client_id", o_auth_app.client_id)
        req.update_param("client_secret", o_auth_app.client_secret)
      end

      def fetch_public_key(o_auth_app, jwt)
        public_key = fetch_public_key_from_json(o_auth_app.jwks, jwt)
        if public_key.empty? && o_auth_app.jwks_uri
          response = SsrfFilter.get(o_auth_app.jwks_uri)
          public_key = fetch_public_key_from_json(response.body, jwt)
        end
        raise Rack::OAuth2::Server::Authorize::BadRequest(:unauthorized_client) if public_key.empty?
        public_key
      end

      def fetch_public_key_from_json(string, jwt)
        json = JSON.parse(string)

View on GitHub (pinned to f96527862d)

Solutions

  1. Make the JWT iss claim exactly the registered OAuthApplication client_id on this pod
  2. Re-check the application registration in account settings and copy the client_id verbatim into the assertion signer
  3. If the app was deleted or rotated, re-register it and update every client
  4. Debug by decoding the client_assertion and printing the iss claim before sending it

Example fix

# before (client_assertion JWT payload)
{'iss': 'my-app-name', 'sub': 'my-app-name', 'aud': token_url, 'exp': 1234567890}
# no application has client_id 'my-app-name' => 400 invalid_request

# after
{'iss': 'a1b2c3d4e5f6...registered_client_id...', 'sub': 'a1b2c3d4e5f6...registered_client_id...', 'aud': token_url, 'exp': 1234567890}
Defensive patterns

Strategy: validation

Validate before calling

payload = JSON::JWT.decode(client_assertion, :skip_verification)
raise 'iss not registered' unless payload['iss'] == REGISTERED_CLIENT_ID

Try / catch

begin
  resp = post(token_url, assertion_params)
rescue TokenRequestError => e
  if e.http_status == 400 && e.body['error'] == 'invalid_request'
    # iss matches no registered client_id: fix the signer configuration
  end
end

Prevention

When it happens

Trigger: POST /api/openid_connect/token with a client_assertion whose iss claim does not match any registered application's client_id: wrong issuer string, app deleted from the pod, or iss missing so the lookup by nil misses.

Common situations: Typo'd or stale client_id in the JWT signer; environment drift (staging client_id sent to a production pod); the OAuth application was removed by its owner or an admin; JWT built with sub as the only identifying claim.

Related errors


AI-assisted analysis of diaspora/diaspora@f96527862d (2026-08-21). Data as JSON: /api/errors/3071222ea48f5a66. Report an issue: GitHub.