Class: ApiAuthentication
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- ApiAuthentication
- Defined in:
- app/models/api_authentication.rb
Overview
== Schema Information
Table name: api_authentications
Database name: primary
id :integer not null, primary key
api_authentication_token :string not null
expires_at :datetime not null
last_used_at :datetime
name :string
permitted_services :text is an Array
revoked_at :datetime
created_at :datetime
account_id :integer not null
Indexes
index_api_authentications_on_account_id (account_id)
index_api_authentications_on_api_authentication_token (api_authentication_token)
index_api_authentications_on_expires_at (expires_at)
index_api_authentications_on_revoked_at (revoked_at)
Constant Summary collapse
- EXPIRATION_OPTIONS =
Common expiration options for UI
{ '1 hour' => 1.hour, '1 day' => 1.day, '1 week' => 1.week, '1 month' => 1.month, '3 months' => 3.months, '6 months' => 6.months, '1 year' => 1.year, 'Never' => 100.years }.freeze
- UPSTREAM_SERVICES =
MCP gateway services that tokens can grant access to.
The gateway provides content tools only. All other services
(PostgreSQL, Ahrefs, AppSignal, Google Analytics, etc.) are
connected directly as standalone MCP servers in each developer's
Cursor config via script/setup_mcp_servers.sh.Content-type permissions control access to sensitive embeddings:
- call_recordings: Search own call recordings (employee's calls only)
- call_recordings_all: Search ALL call recordings (managers/admins)
{ 'content' => { label: 'Content Tools', description: 'Search, posts, FAQs, products, showcases, images, videos, reviews' }, 'call_recordings' => { label: 'My Call Recordings', description: 'Search your own call recording transcripts', sensitive: true }, 'call_recordings_all' => { label: 'All Call Recordings', description: 'Search all employee call recording transcripts (managers only)', sensitive: true }, 'google_analytics' => { label: 'Google Analytics', description: 'GA4 page views, sessions, engagement, traffic sources' }, 'search_console' => { label: 'Search Console', description: 'Google search clicks, impressions, CTR, keyword positions' }, 'google_ads' => { label: 'Google Ads', description: 'Keyword search volume, GAQL queries, campaign data' }, 'ahrefs' => { label: 'Ahrefs SEO', description: 'Backlinks, organic traffic, keyword rankings' }, 'basecamp' => { label: 'Basecamp', description: 'Projects, todos, search, and team collaboration' } }.freeze
- DEFAULT_SERVICES =
Default services.
%w[content].freeze
- SENSITIVE_SERVICES =
Services that require explicit permission -- never granted by default or
by the "all services" fallback for OAuth tokens without scoping. UPSTREAM_SERVICES.select { |_, v| v[:sensitive] }.keys.freeze
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #api_authentication_token ⇒ Object readonly
- #expires_at ⇒ Object readonly
-
#expires_in ⇒ Object
Returns the value of attribute expires_in.
-
#is_guest ⇒ Object
Returns the value of attribute is_guest.
Belongs to collapse
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<ApiAuthentication>
A relation of ApiAuthentications that are active.
-
.expired ⇒ ActiveRecord::Relation<ApiAuthentication>
A relation of ApiAuthentications that are expired.
-
.revoked ⇒ ActiveRecord::Relation<ApiAuthentication>
A relation of ApiAuthentications that are revoked.
Instance Method Summary collapse
- #active? ⇒ Boolean
-
#can_access_service?(service_key) ⇒ Boolean
Check if this token has access to a given upstream service.
-
#effective_services ⇒ Object
Returns the effective services list (with 'content' always included).
- #expired? ⇒ Boolean
-
#masked_token ⇒ Object
Masked token for display (only show first/last 4 chars).
- #revoke! ⇒ Object
- #revoked? ⇒ Boolean
-
#service_labels ⇒ Object
Human-readable labels for the permitted services.
- #status ⇒ Object
- #status_badge_class ⇒ Object
-
#time_until_expiration ⇒ Object
Time until expiration in human-readable format.
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#api_authentication_token ⇒ Object (readonly)
72 |
# File 'app/models/api_authentication.rb', line 72 validates :api_authentication_token, presence: true |
#expires_at ⇒ Object (readonly)
73 |
# File 'app/models/api_authentication.rb', line 73 validates :expires_at, presence: true |
#expires_in ⇒ Object
Returns the value of attribute expires_in.
81 82 83 |
# File 'app/models/api_authentication.rb', line 81 def expires_in @expires_in end |
#is_guest ⇒ Object
Returns the value of attribute is_guest.
81 82 83 |
# File 'app/models/api_authentication.rb', line 81 def is_guest @is_guest end |
Class Method Details
.active ⇒ ActiveRecord::Relation<ApiAuthentication>
A relation of ApiAuthentications that are active. Active Record Scope
77 |
# File 'app/models/api_authentication.rb', line 77 scope :active, -> { where(revoked_at: nil).where('expires_at > ?', Time.current) } |
.expired ⇒ ActiveRecord::Relation<ApiAuthentication>
A relation of ApiAuthentications that are expired. Active Record Scope
79 |
# File 'app/models/api_authentication.rb', line 79 scope :expired, -> { where(expires_at: ..Time.current) } |
.revoked ⇒ ActiveRecord::Relation<ApiAuthentication>
A relation of ApiAuthentications that are revoked. Active Record Scope
78 |
# File 'app/models/api_authentication.rb', line 78 scope :revoked, -> { where.not(revoked_at: nil) } |
Instance Method Details
#active? ⇒ Boolean
91 92 93 |
# File 'app/models/api_authentication.rb', line 91 def active? !expired? && !revoked? end |
#can_access_service?(service_key) ⇒ Boolean
Check if this token has access to a given upstream service
132 133 134 |
# File 'app/models/api_authentication.rb', line 132 def can_access_service?(service_key) effective_services.include?(service_key.to_s) end |
#effective_services ⇒ Object
Returns the effective services list (with 'content' always included)
137 138 139 140 |
# File 'app/models/api_authentication.rb', line 137 def effective_services services = permitted_services.presence || DEFAULT_SERVICES (services | DEFAULT_SERVICES).sort end |
#expired? ⇒ Boolean
83 84 85 |
# File 'app/models/api_authentication.rb', line 83 def expired? expires_at <= Time.current end |
#masked_token ⇒ Object
Masked token for display (only show first/last 4 chars)
115 116 117 118 119 120 121 122 |
# File 'app/models/api_authentication.rb', line 115 def masked_token return nil if api_authentication_token.blank? token = api_authentication_token return token if token.length <= 12 "#{token[0..3]}...#{token[-4..]}" end |
#revoke! ⇒ Object
95 96 97 |
# File 'app/models/api_authentication.rb', line 95 def revoke! update!(revoked_at: Time.current) end |
#revoked? ⇒ Boolean
87 88 89 |
# File 'app/models/api_authentication.rb', line 87 def revoked? revoked_at.present? end |
#service_labels ⇒ Object
Human-readable labels for the permitted services
143 144 145 |
# File 'app/models/api_authentication.rb', line 143 def service_labels effective_services.filter_map { |key| UPSTREAM_SERVICES.dig(key, :label) } end |
#status ⇒ Object
99 100 101 102 103 104 |
# File 'app/models/api_authentication.rb', line 99 def status return 'revoked' if revoked? return 'expired' if expired? 'active' end |
#status_badge_class ⇒ Object
106 107 108 109 110 111 112 |
# File 'app/models/api_authentication.rb', line 106 def status_badge_class case status when 'active' then 'bg-success' when 'expired' then 'bg-warning' when 'revoked' then 'bg-danger' end end |
#time_until_expiration ⇒ Object
Time until expiration in human-readable format
125 126 127 128 129 |
# File 'app/models/api_authentication.rb', line 125 def time_until_expiration return 'Expired' if expired? distance_of_time_in_words(Time.current, expires_at) end |