Class: ApiKeys::ApiKey

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/api_keys/models/api_key.rb

Overview

The core ActiveRecord model representing an API key.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#tokenObject (readonly)

Attributes & Serialization ==

Expose the plaintext token only immediately after creation



20
21
22
# File 'lib/api_keys/models/api_key.rb', line 20

def token
  @token
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/api_keys/models/api_key.rb', line 131

def active?
  !revoked? && !expired?
end

#allows_permission?(required_permission) ⇒ Boolean

Check if this key has a specific permission (alias for allows_scope?)

Parameters:

  • required_permission (String, Symbol)

    The permission to check

Returns:

  • (Boolean)

    true if the key has this permission or has no restrictions



218
219
220
# File 'lib/api_keys/models/api_key.rb', line 218

def allows_permission?(required_permission)
  allows_scope?(required_permission)
end

#allows_scope?(required_scope) ⇒ Boolean

Basic scope check. Assumes scopes are stored as an array of strings.

Behavior depends on whether key_types mode is enabled:

  • Simple mode (no key_types): blank scopes means "unrestricted" (all scopes allowed). This preserves backwards compatibility for apps that don't use scopes at all.
  • Key types mode: blank scopes means "no permissions". When you've configured key types with permission ceilings, an empty scope list should deny access, not silently bypass the entire permission system.

Returns:

  • (Boolean)


194
195
196
197
198
199
200
201
202
203
204
# File 'lib/api_keys/models/api_key.rb', line 194

def allows_scope?(required_scope)
  return true unless respond_to?(:scopes) # Guard clause if loaded before attribute definition

  if scopes.blank?
    # In key_types mode, blank scopes = no access (deny by default)
    # In simple mode, blank scopes = unrestricted (allow by default)
    return !ApiKeys.configuration.key_types.present?
  end

  scopes.include?(required_scope.to_s)
end

#destroyObject

Override destroy to prevent destroying non-revocable keys



176
177
178
179
# File 'lib/api_keys/models/api_key.rb', line 176

def destroy
  raise ApiKeys::Errors::KeyNotRevocableError unless revocable?
  super
end

#destroy!Object



181
182
183
184
# File 'lib/api_keys/models/api_key.rb', line 181

def destroy!
  raise ApiKeys::Errors::KeyNotRevocableError unless revocable?
  super
end

#environment_configObject

Returns the configuration hash for this key's environment



152
153
154
155
# File 'lib/api_keys/models/api_key.rb', line 152

def environment_config
  return nil if environment.blank?
  ApiKeys.configuration.environments&.dig(environment.to_sym)
end

#expired?Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/api_keys/models/api_key.rb', line 127

def expired?
  expires_at? && expires_at <= Time.current
end

#key_type_configObject

Returns the configuration hash for this key's type



146
147
148
149
# File 'lib/api_keys/models/api_key.rb', line 146

def key_type_config
  return nil if key_type.blank?
  ApiKeys.configuration.key_types&.dig(key_type.to_sym)
end

#masked_tokenObject

Provides a masked version of the token for display (e.g., ak_live_••••rj4p) Requires the plaintext token to be available (only right after creation).



224
225
226
227
228
229
230
231
232
233
# File 'lib/api_keys/models/api_key.rb', line 224

def masked_token
  # return "[Token not available]" unless token # No longer needed
  # Show prefix, 4 bullets, last 4 chars of the random part
  # random_part = token.delete_prefix(prefix) # No longer needed
  # "#{prefix}••••#{random_part.last(4)}" # No longer needed

  # Use the stored prefix and last4 attributes
  return "[Invalid Key Data]" unless prefix.present? && last4.present?
  "#{prefix}••••#{last4}"
end

#permissionsArray<String>

Alias for scopes - provides a more user-friendly API that matches the configuration DSL where key types use permissions for scope ceiling. Note: We use a method instead of alias_method because scopes is defined dynamically via the attribute API in the engine initializer.

Returns:

  • (Array<String>)

    The permissions (scopes) assigned to this key



211
212
213
# File 'lib/api_keys/models/api_key.rb', line 211

def permissions
  scopes
end

#public_key_type?Boolean

Returns true if this key type is configured as public AND non-revocable. Only these keys have their plaintext token stored in metadata for later viewing. This is used for publishable keys that are designed to be embedded in distributed apps.

Returns:

  • (Boolean)


160
161
162
163
164
165
# File 'lib/api_keys/models/api_key.rb', line 160

def public_key_type?
  return false if key_type.blank?
  config = key_type_config
  return false if config.nil?
  config[:public] == true && config[:revocable] == false
end

#revocable?Boolean

Returns true if this key can be revoked/destroyed Keys without a key_type (legacy) are always revocable Keys with a key_type check the configuration

Returns:

  • (Boolean)


138
139
140
141
142
143
# File 'lib/api_keys/models/api_key.rb', line 138

def revocable?
  return true if key_type.blank?
  config = key_type_config
  return true if config.nil?
  config.fetch(:revocable, true)
end

#revoke!Object

Instance Methods ==



118
119
120
121
# File 'lib/api_keys/models/api_key.rb', line 118

def revoke!
  raise ApiKeys::Errors::KeyNotRevocableError unless revocable?
  update!(revoked_at: Time.current)
end

#revoked?Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/api_keys/models/api_key.rb', line 123

def revoked?
  revoked_at.present?
end

#scopes=(value) ⇒ Object

Override scopes setter to auto-clean blank values. This handles the common case where form checkboxes submit empty strings. Works for both create and update operations.



28
29
30
31
32
33
34
35
# File 'lib/api_keys/models/api_key.rb', line 28

def scopes=(value)
  cleaned = if value.is_a?(Array)
              value.reject { |s| s.blank? }
            else
              value
            end
  super(cleaned)
end

#viewable_tokenString?

Returns the stored plaintext token for public, non-revocable keys. Returns nil for all other key types (the token is only available at creation time).

Returns:

  • (String, nil)

    The full plaintext token, or nil if not stored



170
171
172
173
# File 'lib/api_keys/models/api_key.rb', line 170

def viewable_token
  return nil unless public_key_type?
  &.dig("token")
end