Class: Fb::Jwt::Auth

Inherits:
Object
  • Object
show all
Defined in:
lib/fb/jwt/auth.rb,
lib/fb/jwt/auth/version.rb,
lib/fb/jwt/auth/service_access_token.rb

Defined Under Namespace

Classes: IssuerNotPresentError, NamespaceNotPresentError, ServiceAccessToken, ServiceTokenClient, TokenExpiredError, TokenNotPresentError, TokenNotValidError

Constant Summary collapse

VERSION =
"0.10.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(token:, key: nil, leeway:, logger:) ⇒ Auth

Returns a new instance of Auth.



39
40
41
42
43
44
# File 'lib/fb/jwt/auth.rb', line 39

def initialize(token:, key: nil, leeway:, logger:)
  @token = token
  @key = key
  @leeway = leeway
  @logger = logger
end

Instance Attribute Details

#keyObject

Returns the value of attribute key.



37
38
39
# File 'lib/fb/jwt/auth.rb', line 37

def key
  @key
end

#leewayObject

Returns the value of attribute leeway.



37
38
39
# File 'lib/fb/jwt/auth.rb', line 37

def leeway
  @leeway
end

#loggerObject

Returns the value of attribute logger.



37
38
39
# File 'lib/fb/jwt/auth.rb', line 37

def logger
  @logger
end

#tokenObject

Returns the value of attribute token.



37
38
39
# File 'lib/fb/jwt/auth.rb', line 37

def token
  @token
end

Class Method Details

.configure {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:

  • _self (Fb::Jwt::Auth)

    the object that the method was called on



15
16
17
# File 'lib/fb/jwt/auth.rb', line 15

def self.configure(&block)
  yield self
end

Instance Method Details

#decode(verify: true, hmac_secret: nil) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/fb/jwt/auth.rb', line 83

def decode(verify: true, hmac_secret: nil)
  JWT.decode(
    token,
    hmac_secret,
    verify,
    exp_leeway: leeway,
    algorithm: 'RS256'
  )
end

#find_application_infoObject



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/fb/jwt/auth.rb', line 93

def find_application_info
  return { application: key } if key

  payload, _header = decode(verify: false)
  application = payload['iss']
  namespace = payload['namespace']

  raise IssuerNotPresentError.new('Issuer is not present in the token') unless application
  raise NamespaceNotPresentError.new('Namespace is not present in the token') unless namespace

  { application: application, namespace: namespace}
end

#public_key(attributes) ⇒ Object



106
107
108
109
110
# File 'lib/fb/jwt/auth.rb', line 106

def public_key(attributes)
  OpenSSL::PKey::RSA.new(
    ServiceTokenClient.new(**attributes).public_key
  )
end

#retrieve_and_decode_public_key(application_details) ⇒ Object



74
75
76
77
78
79
80
81
# File 'lib/fb/jwt/auth.rb', line 74

def retrieve_and_decode_public_key(application_details)
  hmac_secret = public_key(application_details)
  decode(hmac_secret: hmac_secret)
rescue JWT::VerificationError
  logger.debug('First validation failed. Requesting non cached public key')
  hmac_secret = public_key(application_details.merge(ignore_cache: true))
  decode(hmac_secret: hmac_secret)
end

#verify!Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/fb/jwt/auth.rb', line 46

def verify!
  raise TokenNotPresentError.new('Token is not present') if token.blank?

  application_details = find_application_info

  begin
    payload, _header = retrieve_and_decode_public_key(application_details)
  rescue StandardError => e
    error_message = "Token is not valid: error #{e}"
    logger.debug(error_message)
    raise TokenNotValidError.new(error_message)
  end

  # NOTE: verify_iat used to be in the JWT gem, but was removed in v2.2
  # so we have to do it manually
  iat_skew = payload['iat'].to_i - Time.zone.now.to_i

  if iat_skew.abs > leeway.to_i
    error_message = "Token has expired: iat skew is #{iat_skew}, max is #{leeway}"
    logger.debug(error_message)

    raise TokenExpiredError.new(error_message)
  end

  logger.debug 'token is valid'
  payload
end