Class: Rubino::OAuth::ConnectionRepository

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/oauth/connection_repository.rb

Overview

Persistence for OAuth connections backed by the oauth_connections table. Tokens are encrypted on write and decrypted on read through TokenEncryptor, so every hash returned by this repository carries plaintext :access_token/:refresh_token alongside parsed :scopes (Array) and :metadata (Hash) — callers never deal with ciphertext or raw JSON columns.

#upsert is keyed on (provider, account_id): re-authenticating the same provider account updates the existing row in place (preserving its id and created_at) rather than duplicating.

Instance Method Summary collapse

Constructor Details

#initialize(db: nil, encryptor: nil) ⇒ ConnectionRepository

Returns a new instance of ConnectionRepository.



20
21
22
23
# File 'lib/rubino/oauth/connection_repository.rb', line 20

def initialize(db: nil, encryptor: nil)
  @db = db || Rubino.database.db
  @encryptor = encryptor || TokenEncryptor.from_env
end

Instance Method Details

#destroy!(id) ⇒ Object



77
78
79
# File 'lib/rubino/oauth/connection_repository.rb', line 77

def destroy!(id)
  @db[:oauth_connections].where(id: id).delete
end

#find(id) ⇒ Object



60
61
62
63
# File 'lib/rubino/oauth/connection_repository.rb', line 60

def find(id)
  row = @db[:oauth_connections].where(id: id).first
  decrypt(row)
end

#first_for_provider(provider) ⇒ Object



69
70
71
# File 'lib/rubino/oauth/connection_repository.rb', line 69

def first_for_provider(provider)
  decrypt(@db[:oauth_connections].where(provider: provider.to_s).order(:created_at).first)
end

#for_provider(provider) ⇒ Object



65
66
67
# File 'lib/rubino/oauth/connection_repository.rb', line 65

def for_provider(provider)
  @db[:oauth_connections].where(provider: provider.to_s).order(:created_at).map { |r| decrypt(r) }
end

#listObject



73
74
75
# File 'lib/rubino/oauth/connection_repository.rb', line 73

def list
  @db[:oauth_connections].order(:provider, :created_at).map { |r| decrypt(r) }
end

#upsert(provider:, account_id:, access_token:, account_email: nil, refresh_token: nil, expires_at: nil, scopes: [], metadata: {}) ⇒ Hash

Insert or update a connection identified by (provider, account_id). Tokens are encrypted before they hit the database.

Returns:

  • (Hash)

    the freshly-decrypted row as returned by #find: includes all schema columns plus plaintext :access_token and :refresh_token, :scopes (Array<String>) and :metadata (Hash). The :access_token/:refresh_token values are sensitive — never log them.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rubino/oauth/connection_repository.rb', line 33

def upsert(provider:, account_id:, access_token:, account_email: nil, refresh_token: nil, expires_at: nil,
           scopes: [], metadata: {})
  now = Time.now.utc.iso8601
  existing = @db[:oauth_connections].where(provider: provider.to_s, account_id: .to_s).first
  id = existing ? existing[:id] : SecureRandom.uuid

  attrs = {
    id: id,
    provider: provider.to_s,
    account_id: .to_s,
    account_email: ,
    access_token: @encryptor.encrypt(access_token),
    refresh_token: @encryptor.encrypt(refresh_token),
    expires_at: expires_at,
    scopes_json: JSON.generate(scopes),
    metadata_json: JSON.generate(),
    updated_at: now
  }

  if existing
    @db[:oauth_connections].where(id: id).update(attrs)
  else
    @db[:oauth_connections].insert(attrs.merge(created_at: now))
  end
  find(id)
end