class OpenIDConnect::ResponseObject::IdToken

Attributes

access_token[RW]
code[RW]
state[RW]

Public Class Methods

decode(jwt_string, key_or_config) click to toggle source
# File lib/openid_connect/response_object/id_token.rb, line 66
def decode(jwt_string, key_or_config)
  case key_or_config
  when :self_issued
    decode_self_issued jwt_string
  when OpenIDConnect::Discovery::Provider::Config::Response
    jwt = JSON::JWT.decode jwt_string, :skip_verification
    jwt.verify! key_or_config.jwk(jwt.kid)
    new jwt
  else
    new JSON::JWT.decode jwt_string, key_or_config
  end
end
decode_self_issued(jwt_string) click to toggle source
# File lib/openid_connect/response_object/id_token.rb, line 79
def decode_self_issued(jwt_string)
  jwt = JSON::JWT.decode jwt_string, :skip_verification
  jwk = JSON::JWK.new jwt[:sub_jwk]
  raise InvalidToken.new('Missing sub_jwk') if jwk.blank?
  raise InvalidToken.new('Invalid subject') unless jwt[:sub] == jwk.thumbprint
  jwt.verify! jwk
  new jwt
end
new(attributes = {}) click to toggle source
Calls superclass method OpenIDConnect::ConnectObject::new
# File lib/openid_connect/response_object/id_token.rb, line 16
def initialize(attributes = {})
  super
  (all_attributes - [:aud, :exp, :iat, :auth_time, :sub_jwk]).each do |key|
    self.send "#{key}=", self.send(key).try(:to_s)
  end
  self.auth_time = auth_time.to_i unless auth_time.nil?
end
self_issued(attributes = {}) click to toggle source
# File lib/openid_connect/response_object/id_token.rb, line 88
def self_issued(attributes = {})
  attributes[:sub_jwk] ||= JSON::JWK.new attributes.delete(:public_key)
  _attributes_ = {
    iss: 'https://self-issued.me',
    sub: JSON::JWK.new(attributes[:sub_jwk]).thumbprint
  }.merge(attributes)
  new _attributes_
end

Public Instance Methods

to_jwt(key, algorithm = :RS256, &block) click to toggle source
Calls superclass method OpenIDConnect::JWTnizable#to_jwt
# File lib/openid_connect/response_object/id_token.rb, line 38
def to_jwt(key, algorithm = :RS256, &block)
  hash_length = algorithm.to_s[2, 3].to_i
  if access_token
    token = case access_token
    when Rack::OAuth2::AccessToken
      access_token.access_token
    else
      access_token
    end
    self.at_hash = left_half_hash_of token, hash_length
  end
  if code
    self.c_hash = left_half_hash_of code, hash_length
  end
  if state
    self.s_hash = left_half_hash_of state, hash_length
  end
  super
end
verify!(expected = {}) click to toggle source
# File lib/openid_connect/response_object/id_token.rb, line 24
def verify!(expected = {})
  raise ExpiredToken.new('Invalid ID token: Expired token') unless exp.to_i > Time.now.to_i
  raise InvalidIssuer.new('Invalid ID token: Issuer does not match') unless iss == expected[:issuer]
  raise InvalidNonce.new('Invalid ID Token: Nonce does not match') unless nonce == expected[:nonce]

  # aud(ience) can be a string or an array of strings
  unless Array(aud).include?(expected[:audience] || expected[:client_id])
    raise InvalidAudience.new('Invalid ID token: Audience does not match')
  end

  true
end

Private Instance Methods

left_half_hash_of(string, hash_length) click to toggle source
# File lib/openid_connect/response_object/id_token.rb, line 60
def left_half_hash_of(string, hash_length)
  digest = OpenSSL::Digest.new("SHA#{hash_length}").digest string
  Base64.urlsafe_encode64 digest[0, hash_length / (2 * 8)], padding: false
end