Class: StandardId::AuthorizationCode

Inherits:
ApplicationRecord show all
Defined in:
app/models/standard_id/authorization_code.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.default_ttlObject



43
44
45
# File 'app/models/standard_id/authorization_code.rb', line 43

def self.default_ttl
  10.minutes
end

.hash_for(plaintext_code) ⇒ Object



39
40
41
# File 'app/models/standard_id/authorization_code.rb', line 39

def self.hash_for(plaintext_code)
  Digest::SHA256.hexdigest("#{plaintext_code}:#{Rails.configuration.secret_key_base}")
end

.issue!(plaintext_code:, client_id:, redirect_uri:, scope: nil, audience: nil, account: nil, code_challenge: nil, code_challenge_method: nil, metadata: {}) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'app/models/standard_id/authorization_code.rb', line 19

def self.issue!(plaintext_code:, client_id:, redirect_uri:, scope: nil, audience: nil, account: nil, code_challenge: nil, code_challenge_method: nil, metadata: {})
  create!(
    account: ,
    code_hash: hash_for(plaintext_code),
    client_id: client_id,
    redirect_uri: redirect_uri,
    scope: scope,
    audience: audience,
    code_challenge: code_challenge,
    code_challenge_method: code_challenge_method,
    issued_at: Time.current,
    expires_at: Time.current + default_ttl,
    metadata:  || {}
  )
end

.lookup(plaintext_code) ⇒ Object



35
36
37
# File 'app/models/standard_id/authorization_code.rb', line 35

def self.lookup(plaintext_code)
  find_by(code_hash: hash_for(plaintext_code))
end

Instance Method Details

#expired?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'app/models/standard_id/authorization_code.rb', line 51

def expired?
  expires_at <= Time.current
end

#mark_as_used!Object



71
72
73
74
75
76
77
# File 'app/models/standard_id/authorization_code.rb', line 71

def mark_as_used!
  with_lock do
    raise StandardId::InvalidGrantError, "Authorization code already used" if consumed_at.present?
    raise StandardId::InvalidGrantError, "Authorization code expired" if expired?
    update!(consumed_at: Time.current)
  end
end

#pkce_valid?(code_verifier) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/models/standard_id/authorization_code.rb', line 55

def pkce_valid?(code_verifier)
  return true if code_challenge.blank?

  return false if code_verifier.blank?

  case (code_challenge_method || "plain").downcase
  when "s256"
    expected = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier)).delete("=")
    ActiveSupport::SecurityUtils.secure_compare(expected, code_challenge)
  when "plain"
    ActiveSupport::SecurityUtils.secure_compare(code_verifier, code_challenge)
  else
    false
  end
end

#valid_for_client?(client_id) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
# File 'app/models/standard_id/authorization_code.rb', line 47

def valid_for_client?(client_id)
  self.client_id == client_id && consumed_at.nil? && !expired?
end