Authentication & OAuth
Relevant source files
The following files were used as context for generating this wiki page:
Actionmap implements a multi-provider authentication system using OAuth 2.0. The system allows users to authenticate via third-party services, specifically Google and GitHub, rather than maintaining a local password-based system. This approach leverages the OmniAuth middleware to handle the complexities of the OAuth handshake and identity verification.
The authentication flow is centralized in the LoginController, which manages session creation and user provisioning. Upon a successful OAuth callback, the application either identifies an existing user or creates a new record in the database, subsequently storing the user's unique identifier in the Rails session.
System Architecture
The authentication architecture consists of the OmniAuth middleware, dedicated login routes, and the User model. The application is configured to use an active_record_store for sessions, ensuring session persistence across server restarts.
Authentication Flow
The following sequence diagram illustrates the interaction between the User, the Actionmap application, and External OAuth Providers.
Configuration & Providers
Authentication is configured via the OmniAuth::Builder middleware. The application supports two primary providers and includes a "developer" strategy for non-production environments to facilitate testing.
Supported Providers
| Provider | Strategy | Data Requested (Scope) |
|---|---|---|
google_oauth2 | userinfo.email, userinfo.profile | |
| GitHub | github | Default profile and email access |
| Developer | developer | Local development bypass (non-production only) |
Sources: config/initializers/omniauth.rb:42-55, app/models/user.rb:6
Environment Setup
OAuth credentials (Client IDs and Secrets) are managed via Rails credentials. In development and test environments, OmniAuth is configured with mocks to simulate successful logins without external network requests.
# config/initializers/omniauth.rb:51-54
provider :google_oauth2, Rails.application.credentials[:GOOGLE_CLIENT_ID],
Rails.application.credentials[:GOOGLE_CLIENT_SECRET],
{
scope: 'userinfo.email, userinfo.profile',
prompt: 'select_account'
}
Sources: config/initializers/omniauth.rb:43-58
Data Models
The User model and the users table are the primary entities for identity management. The system uses a composite identity based on the OAuth uid and the provider name.
User Schema
| Field | Type | Description |
|---|---|---|
uid | string | Unique identifier provided by the OAuth service. |
provider | integer | Enum representing the service (Google=1, GitHub=2). |
email | string | User's email address from the provider. |
first_name | string | User's first name. |
last_name | string | User's last name. |
Sources: db/schema.rb:108-117, app/models/user.rb:6-9
Model Logic
The User model validates the uniqueness of the uid within the scope of a provider. It also provides helper methods to find users specifically by their provider type.
# app/models/user.rb:21-26
def self.find_google_user(uid)
User.find_by(
provider: User.providers[:google_oauth2],
uid: uid
)
end
Sources: app/models/user.rb:1-33
Login Controller Implementation
The LoginController handles the lifecycle of an authenticated session. It processes callbacks from OmniAuth and manages the transition between guest and authenticated states.
Session Management
create_session: Extracts theomniauth.authhash from the request environment, finds or creates the user record, and setssession[:current_user_id].logout: Clears thecurrent_user_idfrom the session and redirects to the root path.already_logged_in: A before_action filter that prevents logged-in users from accessing the login page, redirecting them to their profile instead.
Sources: app/controllers/login_controller.rb:23-33, app/controllers/login_controller.rb:71-74
User Provisioning
When a user logs in via GitHub, the application handles the lack of split name fields by parsing the name string into first_name and last_name.
# app/controllers/login_controller.rb:56-61
def create_github_user(user_info)
name = user_info['info']['name']
if name.nil?
first_name = 'Anon'
last_name = 'User'
else
first_name, last_name = user_info['info']['name'].strip.split(/\s+/, 2)
end
# ... User.create call
end
Sources: app/controllers/login_controller.rb:56-69
Routing
The authentication system utilizes specific GET and Redirect routes to initiate the OAuth flow and receive callbacks.
| Method | Path | Action | Description |
|---|---|---|---|
| GET | /login | login#login | Displays login options. |
| GET | /login/google | Redirect | Redirects to OmniAuth Google path. |
| GET | /auth/google_oauth2/callback | login#google_oauth2 | Receives Google auth data. |
| GET | /logout | login#logout | Terminates the session. |
Sources: config/routes.rb:5-11
Conclusion
The Actionmap authentication system provides a secure and scalable way to manage user identities by delegating credential management to established OAuth providers. By utilizing OmniAuth and a robust Rails session store, the application ensures that user data is accurately captured and sessions are reliably maintained.