Module: YiffSpace::Auth::Helper

Extended by:
ActiveSupport::Concern
Included in:
ApplicationController, Scoped, RootController
Defined in:
lib/yiffspace/auth/helper.rb

Defined Under Namespace

Modules: ClassMethods, Scoped

Constant Summary collapse

SESSION_CACHE_KEY =

auth/user session values (raw Discord profile + OIDC token claims) can easily exceed a cookie's ~4KB limit, so the session cookie itself only holds an opaque pointer - the real payload lives in Rails.cache (already a hard dependency of this module, see #sync_auth_if_dirty! below), keyed off that pointer.

"yiffspace:auth:session:%s"
SESSION_CACHE_TTL =
30.days
DIRTY_FLAG_KEY =
"yiffspace:auth:dirty:%s"

Instance Method Summary collapse

Instance Method Details

#authObject



41
42
43
44
45
# File 'lib/yiffspace/auth/helper.rb', line 41

def auth
  return AuthInfo::Anonymous.instance if auth_raw.blank?

  AuthInfo.from_session(auth_raw)
end

#auth=(value) ⇒ Object



51
52
53
54
# File 'lib/yiffspace/auth/helper.rb', line 51

def auth=(value)
  value = nil if value.is_a?(AuthInfo::Anonymous)
  write_session_cache(auth_client_config.auth_session_key, value&.to_session)
end

#auth?Boolean

Returns:

  • (Boolean)


47
48
49
# File 'lib/yiffspace/auth/helper.rb', line 47

def auth?
  auth_raw.present? && !auth.anonymous?
end

#auth_client_configObject

Returns the Auth::Client for the current request. In auth engine controllers this is resolved from the routing default set by Engine.for; in host app controllers it falls back to the default registered client. Override in your controller to choose a specific client when multiple are registered.



146
147
148
149
# File 'lib/yiffspace/auth/helper.rb', line 146

def auth_client_config
  client_name = self.client_name
  client_name.present? ? YiffSpace::Auth[client_name.to_sym] : YiffSpace::Auth.default
end

#auth_rawObject



37
38
39
# File 'lib/yiffspace/auth/helper.rb', line 37

def auth_raw
  read_session_cache(auth_client_config.auth_session_key)
end

#client_nameObject



151
152
153
# File 'lib/yiffspace/auth/helper.rb', line 151

def client_name
  respond_to?(:request, true) && request.env[CLIENT_NAME_ENV]
end

#client_name=(value) ⇒ Object



155
156
157
# File 'lib/yiffspace/auth/helper.rb', line 155

def client_name=(value)
  request.env[CLIENT_NAME_ENV] = value.to_sym
end

#full_reset!Object



83
84
85
86
# File 'lib/yiffspace/auth/helper.rb', line 83

def full_reset!
  reset_auth!
  reset_user!
end

#has_permission?(name) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
99
100
# File 'lib/yiffspace/auth/helper.rb', line 96

def has_permission?(name)
  return false unless logged_in?

  auth.permissions.has?(name)
end

#logged_in?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/yiffspace/auth/helper.rb', line 92

def logged_in?
  auth? && user?
end

#require_auth(path) ⇒ Object



88
89
90
# File 'lib/yiffspace/auth/helper.rb', line 88

def require_auth(path)
  redirect_to(path) unless logged_in?
end

#reset_auth!Object



56
57
58
# File 'lib/yiffspace/auth/helper.rb', line 56

def reset_auth!
  write_session_cache(auth_client_config.auth_session_key, nil)
end

#reset_user!Object



79
80
81
# File 'lib/yiffspace/auth/helper.rb', line 79

def reset_user!
  write_session_cache(auth_client_config.user_session_key, nil)
end

#sync_auth_if_dirty!Object

Checks the dirty flag written by the Logto webhook handler. If set, re-fetches the user's current roles and permissions from the Logto Management API and rewrites the session — without waiting for the access token to expire. Call this as a before_action in any controller that needs instant revocation.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/yiffspace/auth/helper.rb', line 108

def sync_auth_if_dirty!
  return unless auth?

  flag_key = format(DIRTY_FLAG_KEY, auth.id)
  return unless Rails.cache.exist?(flag_key)

  Rails.cache.delete(flag_key)

  management = auth_client_config.logto_management
  api_user   = management.get_user_by_id(auth.id)

  if api_user.nil? || api_user.data["isSuspended"]
    full_reset!
    return
  end

  roles       = management.get_user_roles(auth.id)
  permissions = roles.flat_map { |role| management.get_role_scopes(role["id"]) }
                     .pluck("name")
                     .uniq

  self.auth = AuthInfo.new(
    id:          auth.id,
    token:       auth.token,
    roles:       roles.pluck("name"),
    permissions: permissions,
    client_id:   auth.client_id,
  )
end

#url_helpersObject



138
139
140
# File 'lib/yiffspace/auth/helper.rb', line 138

def url_helpers
  YiffSpace::Auth::Engine.for(client_name).routes.url_helpers
end

#userObject



64
65
66
67
68
# File 'lib/yiffspace/auth/helper.rb', line 64

def user
  return UserInfo::Anonymous.instance if user_raw.blank?

  UserInfo.from_session(user_raw)
end

#user=(value) ⇒ Object



74
75
76
77
# File 'lib/yiffspace/auth/helper.rb', line 74

def user=(value)
  value = nil if value.is_a?(UserInfo::Anonymous)
  write_session_cache(auth_client_config.user_session_key, value&.to_session)
end

#user?Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/yiffspace/auth/helper.rb', line 70

def user?
  user_raw.present? && !user.anonymous?
end

#user_rawObject



60
61
62
# File 'lib/yiffspace/auth/helper.rb', line 60

def user_raw
  read_session_cache(auth_client_config.user_session_key)
end