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
- 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
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
- 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
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
- unauthorized_client
- Failed to reshare.
- Failed to add contact to aspect.
- Failed to update the user settings
- Username #{username} should exist before uploading photos.
AI-assisted analysis of diaspora/diaspora@f96527862d (2026-08-21).
Data as JSON: /api/errors/3071222ea48f5a66.
Report an issue: GitHub.