{"record":{"id":"3071222ea48f5a66","repo":"diaspora/diaspora","slug":"invalid-request","errorCode":"invalid_request","errorMessage":"invalid_request","messagePattern":"invalid_request","errorType":"error_code","errorClass":"Rack::OAuth2::Server::Authorize::BadRequest","httpStatus":400,"severity":"error","filePath":"app/controllers/api/openid_connect/token_endpoint_controller.rb","lineNumber":24,"sourceCode":"      skip_before_action :verify_authenticity_token\n\n      def create\n        req = Rack::Request.new(request.env)\n        if req[\"client_assertion_type\"] == \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"\n          handle_jwt_bearer(req)\n        end\n        self.status, headers, self.response_body = Api::OpenidConnect::TokenEndpoint.new.call(request.env)\n        headers.each {|name, value| response.headers[name] = value }\n        nil\n      end\n\n      private\n\n      def handle_jwt_bearer(req)\n        jwt_string = req[\"client_assertion\"]\n        jwt = JSON::JWT.decode jwt_string, :skip_verification\n        o_auth_app = Api::OpenidConnect::OAuthApplication.find_by(client_id: jwt[\"iss\"])\n        raise Rack::OAuth2::Server::Authorize::BadRequest(:invalid_request) unless o_auth_app\n        public_key = fetch_public_key(o_auth_app, jwt)\n        JSON::JWT.decode(jwt_string, JSON::JWK.new(public_key).to_key)\n        req.update_param(\"client_id\", o_auth_app.client_id)\n        req.update_param(\"client_secret\", o_auth_app.client_secret)\n      end\n\n      def fetch_public_key(o_auth_app, jwt)\n        public_key = fetch_public_key_from_json(o_auth_app.jwks, jwt)\n        if public_key.empty? && o_auth_app.jwks_uri\n          response = SsrfFilter.get(o_auth_app.jwks_uri)\n          public_key = fetch_public_key_from_json(response.body, jwt)\n        end\n        raise Rack::OAuth2::Server::Authorize::BadRequest(:unauthorized_client) if public_key.empty?\n        public_key\n      end\n\n      def fetch_public_key_from_json(string, jwt)\n        json = JSON.parse(string)","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/diaspora/diaspora/blob/f96527862dc1ba2e5b95c4196efb0d1f0cc4b6e5/app/controllers/api/openid_connect/token_endpoint_controller.rb#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the JWT iss claim exactly the registered OAuthApplication client_id on this pod","Re-check the application registration in account settings and copy the client_id verbatim into the assertion signer","If the app was deleted or rotated, re-register it and update every client","Debug by decoding the client_assertion and printing the iss claim before sending it"],"exampleFix":"# before (client_assertion JWT payload)\n{'iss': 'my-app-name', 'sub': 'my-app-name', 'aud': token_url, 'exp': 1234567890}\n# no application has client_id 'my-app-name' => 400 invalid_request\n\n# after\n{'iss': 'a1b2c3d4e5f6...registered_client_id...', 'sub': 'a1b2c3d4e5f6...registered_client_id...', 'aud': token_url, 'exp': 1234567890}","handlingStrategy":"validation","validationCode":"payload = JSON::JWT.decode(client_assertion, :skip_verification)\nraise 'iss not registered' unless payload['iss'] == REGISTERED_CLIENT_ID","typeGuard":null,"tryCatchPattern":"begin\n  resp = post(token_url, assertion_params)\nrescue TokenRequestError => e\n  if e.http_status == 400 && e.body['error'] == 'invalid_request'\n    # iss matches no registered client_id: fix the signer configuration\n  end\nend","preventionTips":["Keep the client_id in one config value and derive iss from it","Re-register and propagate credentials after rotating apps","Log the decoded iss of rejected assertions"],"tags":["openid-connect","oauth2","jwt","diaspora","token-endpoint","invalid-request"],"backgroundTag":"unknown-oauth-client","analyzedSha":"f96527862dc1ba2e5b95c4196efb0d1f0cc4b6e5","analyzedAt":"2026-08-21T15:49:49.567Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}