class NOMIS::API::AuthToken

Encapsulates the complexity of generating a JWT bearer token

Attributes

client_key[RW]
client_token[RW]
iat_fudge_factor[RW]
now[RW]

Public Class Methods

new(params = {}) click to toggle source

iat_fudge_factor allows you to correct for time drift between your client and the target server. For instance, if the server time is more than 10s in the future, it will reject any client-generated bearer tokens on the grounds of ‘iat skew too large’ (the timestamp in your payload is too old) In that case, you can pass an iat_fudge_factor of, say, 5, to generate a timestamp tagged 5s into the future and bring it back within the acceptable range.

# File lib/nomis/api/auth_token.rb, line 19
def initialize(params = {})
  self.client_key = OpenSSL::PKey::EC.new( params[:client_key] \
                      || default_client_key(params)
                    )
  self.client_token = params[:client_token] \
                    || default_client_token(params)

  self.iat_fudge_factor = default_iat_fudge_factor(params)
end

Public Instance Methods

bearer_token() click to toggle source
# File lib/nomis/api/auth_token.rb, line 29
def bearer_token
  validate_keys!

  "Bearer #{auth_token}"
end
payload() click to toggle source
# File lib/nomis/api/auth_token.rb, line 35
def payload
  {
    iat: current_timestamp + iat_fudge_factor,
    token: client_token
  }
end
validate_keys!() click to toggle source

Validate that the supplied private key matches the token’s public key. Obviously this step is optional, but when testing locally it’s easy to get one’s private keys in a muddle, and the API gateway’s error message can only say that the generated JWT token does not validate.

# File lib/nomis/api/auth_token.rb, line 47
def validate_keys!
  unless client_public_key_base64 == expected_client_public_key
    raise TokenMismatchError, 
          'Incorrect private key supplied ' \
          + '(does not match public key within token)',
          caller
  end
end

Protected Instance Methods

auth_token() click to toggle source
# File lib/nomis/api/auth_token.rb, line 58
def auth_token
  JWT.encode(payload, client_key, 'ES256')
end
client_public_key_base64() click to toggle source
# File lib/nomis/api/auth_token.rb, line 62
def client_public_key_base64
  client_public_key = OpenSSL::PKey::EC.new client_key
  client_public_key.private_key = nil
  Base64.strict_encode64(client_public_key.to_der)
end
current_timestamp() click to toggle source
# File lib/nomis/api/auth_token.rb, line 72
def current_timestamp
  now || Time.now.to_i
end
default_client_key(params = {}) click to toggle source
# File lib/nomis/api/auth_token.rb, line 76
def default_client_key(params = {})
  path = params[:client_key_file] || ENV['NOMIS_API_CLIENT_KEY_FILE']
  path ? read_client_key_file(path) : nil
end
default_client_token(params = {}) click to toggle source
# File lib/nomis/api/auth_token.rb, line 81
def default_client_token(params = {})
  path = params[:client_token_file] || ENV['NOMIS_API_CLIENT_TOKEN_FILE']
  path ? read_client_key_file(path) : nil
end
default_iat_fudge_factor(params={}) click to toggle source
# File lib/nomis/api/auth_token.rb, line 86
def default_iat_fudge_factor(params={})
  ENV['NOMIS_API_IAT_FUDGE_FACTOR'].to_i || 0
end
expected_client_public_key() click to toggle source
# File lib/nomis/api/auth_token.rb, line 68
def expected_client_public_key
  JWT.decode(client_token, nil, nil)[0]['key']
end
read_client_key_file(path) click to toggle source
# File lib/nomis/api/auth_token.rb, line 94
def read_client_key_file(path)
  File.open(File.expand_path(path), 'r').read
end
read_client_token_file(path) click to toggle source
# File lib/nomis/api/auth_token.rb, line 90
def read_client_token_file(path)
  File.open(File.expand_path(path), 'r').read.chomp('')
end