The Action API requires the user to use edit tokens (ie. write operations are only allowed if the user includes a token that has been fetched in a separate request, to protect against CSRF attacks). This does not seem like a great fit for a REST API workflow. Is there a better way?
Options that come to mind:
- Just deal with it. Add a token endpoint to the REST API; clients are required to call it first and fetch a token. Any write endpoint can return a token error (Wikimedia has MediaWiki configured with short session lifespans) in which case the client is required to fetch a new token and resubmit the request. This seems inconvenient but most clients do it already since they interface with the Action API directly, so not that much of a change.
- Use some kind of CSRF-safe authentication or request signing, and relax CSRF requirements when not actually needed (cf. T126257: The API should not require CSRF tokens for an OAuth request).
- Use OAuth. The problem here is that unlike session cookies, OAuth cannot be transparently proxied as the signature is based on the request URL. So the REST service would have to be able to verify OAuth signatures (not hard since there are libraries for it, but the data is stored in MediaWiki so the service would have to access it somehow) and authenticate to the action API in some alternative way.
- Use API tokens. This would require a new authentication module for MediaWiki, plus T126257, but unlike OAuth it can be proxied transparently. Stealing such a token could allow impersonating the user, but that does not seem any more insecure than the long-lived token cookies already used by MediaWiki. Also, it could be bound to a single REST service (Reading Lists, for example, is not super sensitive).
- Use double-submit CSRF; ie. instead of storing the CSRF in the session, just have the client store it in a cookie and submit as both cookie and POST data, and compare on the server. This is less secure than session CSRF, though. (Slightly more secure if the cookie is initially obtained from MediaWiki and signed in some way.)
- Force requests to trigger CORS (e.g. Content-Type: application/json), so web clients can only send requests from trusted domains. (Non-web clients are not affected by CSRF anyway.) Then find some way to exempt requests proxied by the REST service from having to include a CSRF token.
The current strategy is to require a CSRF token to be passed to the edit end point. Unauthenticated, read-only end points are returning access-control-allow-origin:* (which normally disables the sending of credentials), and discard any cookies sent anyway to ensure that only publicly accessible information is returned. We chose not to wrap the CSRF token retrieval end point itself at this point.