Aha Builder Core Client
Ruby client for Aha! Builder core authentication services which provides login and signup using email/password, social logins (Google, Github, Microsoft), SAML SSO and password reset.
Installation
Add to your Gemfile:
gem "aha_builder_core", path: "engines/builder_core/client"
Configuration
No configuration is necessary and no environment variables are necessary.
Authentication Flow
The authentication UI is provided completely by the core system. During authentication the user is redirected to the login page, and will return (via HTTP redirect) to the /callback URL when authentication is complete. Your application must implement a callback action at /callback to receive the code. Any value passed in as state is returned verbatim to the callback.
Protection against CSRF atacks is handled internally by the Aha::Auth library and there is no need to use a nonce in the state parameter.
Generate Login URL
Redirect users to the authentication and signup UI:
url = Aha::Auth.login_url(
state: { return_to: "/" }.to_json,
)
redirect_to url
Redirecting to the login_url must be done with a full page load. It will not work using XHR.
Exchange Authorization Code
In the /callback action callback, you must exchange the code for a session token and refresh token:
result = Aha::Auth.authenticate_with_code(code: params[:code])
# => {
# session_token: "...",
# refresh_token: "...",
# expires_at: Time,
# user: {
# id: "user-uuid",
# first_name: "Jane",
# last_name: "Doe",
# email: "[email protected]",
# email_verified: true
# }
# }
User Object
The user object returned contains the authenticated user's profile information from the Builder Core system:
id: The unique identifier for the user in Builder Corefirst_name: User's first name. first_name is optional and may not be present.last_name: User's last name. last_name is optional and may not be present.email: User's email addressemail_verified: Boolean indicating if the email has been verified
Linking to Local User Records
You can use the returned user object to create or update local user records in your application:
# In your callback action
result = Aha::Auth.authenticate_with_code(code: params[:code])
# Find or create a local user record linked to Builder Core user
local_user = User.find_or_initialize_by(auth_identifier: result[:user]["id"])
# Update local user attributes
local_user.update!(
email: result[:user][:email],
first_name: result[:user][:first_name],
last_name: result[:user][:last_name],
email_verified: result[:user][:email_verified]
)
# Store tokens in session or database
session[:session_token] = result[:session_token]
session[:refresh_token] = result[:refresh_token]
session[:user_id] = local_user.id
# Redirect to application
redirect_to root_path
Validate Session
Validate a session token (with automatic refresh):
session = Aha::Auth.validate_session(session_token, refresh_token: refresh_token)
if session.valid?
user_id = session.user_id
# If tokens were refreshed, update stored tokens
if session.refreshed?
new_session_token = session.new_session_token
new_refresh_token = session.new_refresh_token
end
else
# Redirect to login
end
Logout
Aha::Auth.logout(session_token: session_token)
User Management
Server-to-server operations (requires api_key):
# Create user
user = Aha::Auth.users.create(
email: "[email protected]",
first_name: "Jane",
last_name: "Doe",
password: "secure_password"
)
# Find user
user = Aha::Auth.users.find(user_id)
# Update user
user = Aha::Auth.users.update(user_id, first_name: "Janet")
# Delete user
Aha::Auth.users.delete(user_id)
# List users
result = Aha::Auth.users.list(page: 1, per_page: 50)
result[:users] # Array of User objects
result[:total] # Total count
Session Management
# List active sessions for a user
sessions = Aha::Auth.sessions.list(user_id: user_id)
# Revoke a session
Aha::Auth.sessions.revoke(session_id)
Error Handling
begin
Aha::Auth.validate_session(token)
rescue Aha::Auth::InvalidTokenError
# Token is malformed or has invalid signature
rescue Aha::Auth::ExpiredTokenError
# Token expired and refresh failed
rescue Aha::Auth::RateLimitError => e
# Rate limited, retry after e.retry_after seconds
rescue Aha::Auth::
# Invalid API key
rescue Aha::Auth::NotFoundError
# Resource not found
rescue Aha::Auth::NetworkError => e
# Connection failed, original error in e.original_error
rescue Aha::Auth::ApiError => e
# Other API error, check e.status and e.body
end