Module: BetterAuth::Session

Defined in:
lib/better_auth/session.rb

Class Method Summary collapse

Class Method Details

.cached_session(ctx, token, disable_cookie_cache:, sensitive:) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/better_auth/session.rb', line 38

def cached_session(ctx, token, disable_cookie_cache:, sensitive:)
  config = ctx.context.session_config[:cookie_cache] || {}
  return nil if disable_cookie_cache || sensitive || !config[:enabled]

  payload = Cookies.get_cookie_cache(
    ctx,
    secret: ctx.context.secret,
    strategy: config[:strategy] || "compact",
    version: config[:version],
    cookie_prefix: ctx.context.options.advanced[:cookie_prefix] || "better-auth",
    is_secure: ctx.context.auth_cookies[:session_data].name.start_with?(Cookies::SECURE_COOKIE_PREFIX)
  )
  return nil unless payload
  return nil if payload["session"]["token"] && payload["session"]["token"] != token

  result = {session: payload["session"], user: payload["user"]}
  Cookies.set_cookie_cache(ctx, result, false) if should_refresh_cookie_cache?(config, payload)
  result
end

.expired?(session) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
66
# File 'lib/better_auth/session.rb', line 63

def expired?(session)
  expires_at = normalize_time(session["expiresAt"])
  expires_at && expires_at <= Time.now
end

.find_current(ctx, disable_cookie_cache: false, disable_refresh: false, sensitive: false) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/better_auth/session.rb', line 9

def find_current(ctx, disable_cookie_cache: false, disable_refresh: false, sensitive: false)
  if ctx.context.current_session
    return ctx.context.current_session
  end

  token_cookie = ctx.context.auth_cookies[:session_token]
  token = ctx.get_signed_cookie(token_cookie.name, ctx.context.secret)
  return nil unless token

  cached = cached_session(ctx, token, disable_cookie_cache: disable_cookie_cache, sensitive: sensitive)
  if cached
    ctx.context.set_current_session(cached) if ctx.context.respond_to?(:set_current_session)
    return cached
  end

  found = ctx.context.internal_adapter.find_session(token)
  return missing_session(ctx) unless found

  session = stringify_keys(found[:session] || found["session"])
  user = stringify_keys(found[:user] || found["user"])
  return missing_session(ctx) if expired?(session)

  result = {session: session, user: user}
  result = refresh_session(ctx, result) if should_refresh?(ctx, session, disable_refresh)
  Cookies.set_cookie_cache(ctx, result, false)
  ctx.context.set_current_session(result) if ctx.context.respond_to?(:set_current_session)
  result
end

.missing_session(ctx) ⇒ Object



58
59
60
61
# File 'lib/better_auth/session.rb', line 58

def missing_session(ctx)
  Cookies.delete_session_cookie(ctx)
  nil
end

.normalize_time(value) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/better_auth/session.rb', line 106

def normalize_time(value)
  return value if value.is_a?(Time)
  return Time.at(value / 1000.0) if value.is_a?(Integer) && value > 10_000_000_000
  return Time.at(value) if value.is_a?(Integer)
  return nil if value.nil?

  Time.parse(value.to_s)
end

.refresh_session(ctx, result) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/better_auth/session.rb', line 78

def refresh_session(ctx, result)
  now = Time.now
  expires_at = now + ctx.context.session_config[:expires_in].to_i
  updated = ctx.context.internal_adapter.update_session(
    result[:session]["token"],
    "expiresAt" => expires_at,
    "updatedAt" => now
  )
  session = stringify_keys(updated || result[:session]).merge("expiresAt" => expires_at, "updatedAt" => now)
  refreshed = {session: session, user: result[:user]}
  Cookies.set_session_cookie(ctx, refreshed, Cookies.dont_remember?(ctx))
  refreshed
end

.should_refresh?(ctx, session, disable_refresh) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
# File 'lib/better_auth/session.rb', line 68

def should_refresh?(ctx, session, disable_refresh)
  return false if disable_refresh

  update_age = ctx.context.session_config[:update_age].to_i
  return true if update_age.zero?

  updated_at = normalize_time(session["updatedAt"])
  updated_at && updated_at + update_age <= Time.now
end

Returns:

  • (Boolean)


92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/better_auth/session.rb', line 92

def should_refresh_cookie_cache?(config, payload)
  refresh_cache = config[:refresh_cache]
  return false if refresh_cache == false || refresh_cache.nil?

  max_age = (config[:max_age] || 60 * 5).to_i
  update_age = if refresh_cache.is_a?(Hash)
    (refresh_cache[:update_age] || refresh_cache["updateAge"] || refresh_cache["update_age"]).to_i
  else
    (max_age * 0.8).to_i
  end
  updated_at = payload["updatedAt"].to_i
  updated_at.positive? && updated_at + (update_age * 1000) <= (Time.now.to_f * 1000).to_i
end

.stringify_keys(value) ⇒ Object



115
116
117
118
119
120
# File 'lib/better_auth/session.rb', line 115

def stringify_keys(value)
  return value.each_with_object({}) { |(key, object_value), result| result[key.to_s] = stringify_keys(object_value) } if value.is_a?(Hash)
  return value.map { |entry| stringify_keys(entry) } if value.is_a?(Array)

  value
end