Pros and Cons of JSON Web Tokens

JSON Web Tokens (JWTs) are a standard for OAuth 2.0 token format. The current (as of February 2020) implementation of OAuth 2.0 for MediaWiki in Extension:OAuth uses JWTs for tokens. There is a question about whether we should keep doing this. This page is for talking about the pros and cons of JWTs for MediaWiki and specifically Wikimedia sites.

Background edit

In OAuth 2.0, a token is a string of characters that represents a grant of rights by a user to a client application for accessing resources on a server. For example, if Alice wants to use Program X to manage her Wikipedia watchlist, she could obtain a token representing the read and edit watchlist right and Program X could use that token to read and update her watchlist with the Action API.

Most of the OAuth 2.0 spec is about how to obtain and use these tokens. In the spec, the token format is left up to the implementation. The spec states that "The string is usually opaque to the client.".[1]

There are two main strategies for formatting tokens.

The first is to use a randomly-generated string (typically a few hundred bits). On the server side, a representation of the grant of rights is stored in a database, with the token as a key. Something like:

OAuth 2.0 Grant Table (example)
Token User ID Developer ID Rights Other stuff...
AAAAAAAA 1 7 read and edit watchlist
BBBBBBBB 2 5 edit pages
CCCCCCC 2 4 read pages, read preferences, edit preferences

When the client app sends the token to the server, it can look up the token in the table, and check if the app has the rights to do what it's asking to do.

Another technique is to encode the grant information into the token itself, described as self-encoded access tokens. This is the approach used by JSON Web Tokens. The grant data is stored in a JSON blob, which is then compressed and digitally signed by the server; the resulting data is the token. When the token is presented to the server, the server can decode it, check the digital signature, and check the app's rights without doing a database lookup. JSON Web Tokens are a standard defined in RFC 7519.

Pros edit

  • Makes it easier to build APIs that support OAuth 2.0 outside of MediaWiki. Because the API server doesn't need to access a database table to determine if a token is valid, API servers built outside of MediaWiki are somewhat easier to build. They may still need to use the database or a MediaWiki API to get the data the user is asking for, though!
  • Lets client developers inspect tokens for debugging or other work. A client developer can use a JWT parser to determine what the grants are or the metadata about the grant. That's useful for debugging errors, validating that the token is complete and well-formatted, or just to figure out how to use the token.[citation needed]
  • JWTs are popular. Atlassian, Google, Microsoft and other platforms use JWTs for their OAuth 2.0 tokens. Authorization services like Okta and Auth0 also use them. Client developers are getting familiar with the tools.

Cons edit

  • Tokens should be opaque to clients. The OAuth 2 spec itself says "The string is usually opaque to the client".[1] Clients should not be concerned with trying to determine if a token is complete or well-formed, they should just use it.
  • Using non-opaque tokens means the data in the tokens becomes part of the public interface. We must know what that data is, and must follow our deprecation policies if that data is going to be changed.
  • Client developers can and should fetch metdata through better-defined endpoints. The set of grants/scopes are already provided via /oauth2/resources/scopes. Information about the authorized user is provided via /oauth2/resources/profile, and can also be fetched via more generic endpoints such as the Action API's userinfo. Additional data can much more easily be provided via API endpoints than by making the token even larger.
  • Self-encoded access tokens are already an order of magnitude larger. The access token must be stored by the client and sent with every request.[2] A typical random token might reach the high tens of bytes, while a typical JWT token can easily reach the high hundreds.
  • Our existing users are used to long-lived access tokens. MediaWiki's traditional cookie-based authentication uses cookies with an expiry of 1 year. MediaWiki's OAuth 1.0a implementation uses access tokens that never expire (they last until revoked). The first "pro" claimed above requires access tokens with lifetimes measured in minutes.[3]
  • Short-lived access tokens harder for clients to work with. Short-lived access tokens require frequent reauthorization, typically using longer-lived "refresh" tokens. This requires clients implement logic to track multiple tokens and their lifetimes, with frequent refreshes.[3]
    • Further, in the current implementation of OAuth 2 the refresh tokens are not stored in a way that they can be particularly long-lived.[4] Fixing this would require a schema change.
  • It's possible to support API development outside of MediaWiki in other ways. Restbase services have already established patterns to do this.[citation needed] These patterns additionally allow clients to take advantage of MediaWiki authentication methods that they are already using, rather than being forced to implement OAuth 2.
    • If established patterns do not actually exist or are insufficient, we could easily establish a new pattern (using JWTs, but not the same JWT used for OAuth 2) that would avoid the various "cons" that reusing MediaWiki's OAuth 2 JWTs for this purpose would cause.
  • Supporting JWTs as access tokens requires[5] managing RSA key files for developers, CI, and production. This has already caused multiple bugs in Wikimedia production and CI. This will similarly be a complication for developers and third-party users of MediaWiki's OAuth extension.
  • JWTs can still be provided, if desired, via a REST endpoint. The OAuth 1.0a implementation already provides JWT via Special:OAuth/identify. The /oauth2/resources/profile endpoint could similarly supply a JWT, or a new endpoint (e.g. /oauth2/resources/jwt) could easily be provided for that purpose. Further, the contents of this JWT could be determined without needing to include data required by the league/oauth2-server library implementing the OAuth 2 protocol.
  • MediaWiki does not need self-encoded access tokens. Our implementation already hits the database for every request to check for revocation. There would be negligible additional overhead to fetch the other data required to handle the request (as our OAuth 1.0a implementation already does).
    • However, a schema change would be required to store the additional data required, or we'd need to take advantage of RFC 6749 § 3.3 being optional.
  • Many other things are popular. If popularity is a "pro", does that mean we should also add intrusive advertising, violation of user privacy to the maximum extent we're capable, and so on?

References edit

  1. 1.0 1.1 https://tools.ietf.org/html/rfc6749#section-1.4
  2. HTTP/2 can reduce this, but does not completely eliminate it.
  3. 3.0 3.1 https://www.oauth.com/oauth2-servers/access-tokens/access-token-lifetime/
  4. This is due to early misunderstanding of just what the "refresh tokens" were used for.
  5. Technically JWT doesn't require RSA, tokens can be signed with a shared secret instead. But league/oauth2-server implements only RSA.