Module: Aha::Auth

Defined in:
lib/aha/auth.rb,
lib/aha/auth/user.rb,
lib/aha/auth/client.rb,
lib/aha/auth/errors.rb,
lib/aha/auth/session.rb,
lib/aha/auth/token_cache.rb,
lib/aha/auth/configuration.rb,
lib/aha/auth/users_resource.rb,
lib/aha/auth/sessions_resource.rb

Defined Under Namespace

Classes: ApiError, BadRequestError, Client, Configuration, ConfigurationError, Error, ExpiredTokenError, ForbiddenError, InvalidTokenError, NetworkError, NotFoundError, RateLimitError, RevokedSessionError, Session, SessionsResource, TokenCache, UnauthorizedError, User, UsersResource

Constant Summary collapse

CONFIGURATION =
Concurrent::Atom.new(Configuration.new)
CLIENT =
Concurrent::Atom.new(nil)
USERS_RESOURCE =
Concurrent::Atom.new(nil)
SESSIONS_RESOURCE =
Concurrent::Atom.new(nil)

Class Method Summary collapse

Class Method Details

.authenticate_with_code(code:, cookies:) ⇒ Hash

Exchange an authorization code for tokens

Parameters:

  • code (String)

    The authorization code from the callback (may include nonce)

  • cookies (Hash)

    Cookies hash containing the nonce for CSRF verification

Returns:

  • (Hash)

    Token response with :session_token, :refresh_token, :expires_at, :user



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/aha/auth.rb', line 77

def authenticate_with_code(code:, cookies:)
  # Split the code and nonce if present
  actual_code, nonce = code.split(".", 2)

  # Verify CSRF protection if nonce is present
  if nonce
    cookie_nonce = cookies[:auth_nonce]

    # Verify nonce matches
    if cookie_nonce.blank? 
      raise "CSRF verification failed: nonce missing in cookie"
    end

    if cookie_nonce != nonce
      raise "CSRF verification failed: nonce mismatch"
    end

    # Clear the nonce from session after verification
    cookies.delete(:auth_nonce)
  else
    # If we fon't have a none, we can't verify CSRF.
    raise "CSRF verification failed: unable to verify nonce"
  end

  client.authenticate_with_code(code: actual_code)
end

.configurationObject



28
29
30
# File 'lib/aha/auth.rb', line 28

def configuration
  CONFIGURATION.value
end

.configure {|CONFIGURATION.value| ... } ⇒ Object

Yields:



32
33
34
# File 'lib/aha/auth.rb', line 32

def configure
  yield(CONFIGURATION.value)
end

.login_url(cookies:, state: nil) ⇒ String

Generate login URL for redirecting users to the auth server

Parameters:

  • cookies (Hash)

    Cookies hash to store the nonce for CSRF verification

  • state (String) (defaults to: nil)

    Optional state parameter to pass through the auth flow

Returns:

  • (String)

    The login URL



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/aha/auth.rb', line 48

def (cookies:, state: nil)
  # Generate a nonce for CSRF protection
  nonce = SecureRandom.hex(10)

  # Store nonce in the client's session if provided
  cookies[:auth_nonce] = nonce

  # Encode the state with nonce
  state_data = {
    tunneled_state: state,
    nonce: nonce,
  }

  encoded_state = Base64.urlsafe_encode64(state_data.to_json, padding: false)

  params = {
    client_id: configuration.client_id,
    state: encoded_state
  }

  query = URI.encode_www_form(params)
  "#{configuration.server_url}/auth_ui/start?#{query}"
end

.logout(session_token:) ⇒ Boolean

Logout and revoke the session

Parameters:

  • session_token (String)

    The session token to revoke

Returns:

  • (Boolean)

    true if successful



125
126
127
# File 'lib/aha/auth.rb', line 125

def logout(session_token:)
  client.logout(session_token: session_token)
end

.refresh_tokens(refresh_token:) ⇒ Hash

Refresh tokens using a refresh token

Parameters:

  • refresh_token (String)

    The refresh token

Returns:

  • (Hash)

    Token response with :session_token, :refresh_token, :expires_at



108
109
110
# File 'lib/aha/auth.rb', line 108

def refresh_tokens(refresh_token:)
  client.authenticate_with_refresh_token(refresh_token: refresh_token)
end

.reset_configuration!Object



36
37
38
39
40
41
# File 'lib/aha/auth.rb', line 36

def reset_configuration!
  CONFIGURATION.reset(Configuration.new)
  CLIENT.reset(nil)
  USERS_RESOURCE.reset(nil)
  SESSIONS_RESOURCE.reset(nil)
end

.sessionsSessionsResource

Access the sessions API resource

Returns:



140
141
142
143
# File 'lib/aha/auth.rb', line 140

def sessions
  SESSIONS_RESOURCE.compare_and_set(nil, SessionsResource.new(client))
  SESSIONS_RESOURCE.value
end

.usersUsersResource

Access the users API resource

Returns:



132
133
134
135
# File 'lib/aha/auth.rb', line 132

def users
  USERS_RESOURCE.compare_and_set(nil, UsersResource.new(client))
  USERS_RESOURCE.value
end

.validate_session(session_token, refresh_token: nil) ⇒ Session

Validate a session token

Parameters:

  • session_token (String)

    The JWT session token

  • refresh_token (String, nil) (defaults to: nil)

    Optional refresh token for automatic refresh

Returns:

  • (Session)

    Session validation result



117
118
119
# File 'lib/aha/auth.rb', line 117

def validate_session(session_token, refresh_token: nil)
  client.validate_session(session_token, refresh_token: refresh_token)
end