Update Assertion strategy claims and request parameters

Created by: jhmoore

This started long ago as a fix to get this gem working with the Google two-legged OAuth2 service account use case, but evolved into a general fix for several issues. See the message history here for the complete context, but the short version is that this PR:

  • Updates the assertion_type request parameter to grant_type. This was changed in OAuth2 draft v11 in 2010(!). See the final RFC.
  • Allows any string to be set as a JWT claim key, rather than restricting to a specific set of four. Relevant RFCs are 7519 and 7523. There are some standard/expected ones (iss, sub, aud, exp, etc) but any endpoint can specify a requirement for the presence (or absence!) of any custom key they want.
  • Allows the use of any encoding method supported by the jwt gem, rather than just HS256 or RS256. See their documentation for the list.
  • Adds a bunch of specs!

The downside:

  • There are breaking changes to Assertion#get_token. Previously, the arguments looked like:
get_token(params, opts = {})

Now, the arguments are:

get_token(claims, encoding_opts, request_opts = {}, response_opts = {})

One of the reasons the Google use case did not work before was that Google requires a custom JWT claim key named scope. However, params[:scope] was a special key that was getting put into the request body itself -- having one params argument meant that this method could not differentiate between arguments intended to be put into the JWT, and arguments intended to be used elsewhere. In addition, like in the example of scope, there could be collisions between the two concepts.

Showing what an identical call might look like, translated from old to new:

OLD:

params = {
  :iss => 'oauth@example.com',
  :scope => 'foo',
  :aud => 'https://example.com/oauth2/token',
  :exp => 1.hour.from_now.to_i,
  :prn => 'swayze@roadhouse.example.com',
  :hmac_secret => 'secret!'
}

get_token(params)

NEW:

claims = {
  :iss => 'oauth@example.com',
  :aud => 'https://example.com/oauth2/token',
  :exp => 1.hour.from_now.to_i,
  :prn => 'swayze@roadhouse.example.com',
}

get_token(claims, {:algorithm => 'HS256', :key => 'secret!'}, {:scope => 'foo'})

Note that there is now the slight additional overhead of needing to know which encoding method you want to use. If you were passing in params[:hmac_secret] before, this file was inferring 'HS256' -- if you were passing in params[:private_key], it was inferring 'RS256'. See the list in RFC 7518 of supported algorithms -- including some that may be more strongly recommended in the future.

It's also worth noting that this PR expressly does not try to validate the presence of claim keys that are listed as required in the JWT for OAuth2 RFC. There are definitely endpoints that do not conform to that RFC (e.g. I think Google does not, in some cases), and folks should still be able to use this gem for those services. If there are endpoints that are strict about requiring the RFC-mandated keys, then they will enforce that behavior on their end.

Merge request reports

Loading
Loading