Vulcan OKTA Configuration Guide - mitre/vulcan GitHub Wiki
Okta OIDC Setup Guide for Vulcan
Overview
This guide covers the complete setup for Okta authentication in Vulcan, including solutions for common issues like:
- Users not being prompted for 2FA on subsequent logins
- Session persistence issues
- Proper logout implementation
- CSRF token problems
Working Environment Variables Configuration
Based on a proven working setup, here's the complete configuration for Okta authentication:
# Core OIDC Settings
VULCAN_ENABLE_LDAP=false
VULCAN_ENABLE_OIDC=true
VULCAN_OIDC_PROVIDER_TITLE=OKTA
# Okta Domain and URLs
VULCAN_OIDC_HOST=your-domain.okta.com
VULCAN_APP_URL=https://your-vulcan-app.com
# Okta OAuth2 Endpoints (using default authorization server)
VULCAN_OIDC_ISSUER_URL=https://your-domain.okta.com/oauth2/default
VULCAN_OIDC_AUTHORIZATION_URL=https://your-domain.okta.com/oauth2/default/v1/authorize
VULCAN_OIDC_TOKEN_URL=https://your-domain.okta.com/oauth2/default/v1/token
VULCAN_OIDC_USERINFO_URL=https://your-domain.okta.com/oauth2/default/v1/userinfo
VULCAN_OIDC_JWKS_URI=https://your-domain.okta.com/oauth2/default/v1/keys
# Client Configuration
VULCAN_OIDC_CLIENT_ID=your-okta-client-id
VULCAN_OIDC_CLIENT_SECRET=your-okta-client-secret
VULCAN_OIDC_REDIRECT_URI=https://your-vulcan-app.com/users/auth/oidc/callback
# Optional: Force re-authentication with 2FA
# Add this to vulcan.yml under oidc.args section:
# prompt: 'login'
Kubernetes ConfigMap Example
apiVersion: v1
kind: ConfigMap
metadata:
name: vulcan-oidc-config
data:
VULCAN_ENABLE_LDAP: "false"
VULCAN_ENABLE_OIDC: "true"
VULCAN_OIDC_PROVIDER_TITLE: "OKTA"
VULCAN_OIDC_HOST: "your-domain.okta.com"
VULCAN_APP_URL: "https://your-vulcan-app.com"
VULCAN_OIDC_ISSUER_URL: "https://your-domain.okta.com/oauth2/default"
VULCAN_OIDC_AUTHORIZATION_URL: "https://your-domain.okta.com/oauth2/default/v1/authorize"
VULCAN_OIDC_USERINFO_URL: "https://your-domain.okta.com/oauth2/default/v1/userinfo"
VULCAN_OIDC_TOKEN_URL: "https://your-domain.okta.com/oauth2/default/v1/token"
VULCAN_OIDC_REDIRECT_URI: "https://your-vulcan-app.com/users/auth/oidc/callback"
VULCAN_OIDC_JWKS_URI: "https://your-domain.okta.com/oauth2/default/v1/keys"
Okta Application Setup
-
Create Application in Okta Admin Console:
- Application type:
Web
- Grant type:
Authorization Code
- Sign-in redirect URIs:
https://your-vulcan-app.com/users/auth/oidc/callback
- Sign-out redirect URIs:
https://your-vulcan-app.com/
- Controlled access: Configure based on your organization's needs
- Application type:
-
Important Notes:
- Using
/oauth2/default
authorization server is recommended - Ensure your Okta app has the correct redirect URI that matches exactly
- The redirect URI must use HTTPS in production
- Using
Fixing 2FA Re-authentication Issues
If users are not being prompted for 2FA on subsequent logins, add a custom vulcan.yml
:
defaults: &defaults
oidc:
enabled: true
strategy: :openid_connect
title: "OKTA"
args:
name: :oidc
scope:
- :openid
- :email
- :profile
uid_field: 'sub'
response_type: :code
# Force re-authentication with 2FA
prompt: 'login'
issuer: <%= ENV['VULCAN_OIDC_ISSUER_URL'] %>
client_auth_method: :secret
client_signing_alg: :RS256
nonce: <%= proc { SecureRandom.hex(32) } %>
client_options:
port: 443
scheme: https
host: <%= ENV['VULCAN_OIDC_HOST'] %>
identifier: <%= ENV['VULCAN_OIDC_CLIENT_ID'] %>
secret: <%= ENV['VULCAN_OIDC_CLIENT_SECRET'] %>
redirect_uri: <%= ENV['VULCAN_OIDC_REDIRECT_URI'] %>
authorization_endpoint: <%= ENV['VULCAN_OIDC_AUTHORIZATION_URL'] %>
token_endpoint: <%= ENV['VULCAN_OIDC_TOKEN_URL'] %>
userinfo_endpoint: <%= ENV['VULCAN_OIDC_USERINFO_URL'] %>
jwks_uri: <%= ENV['VULCAN_OIDC_JWKS_URI'] %>
# For proper logout (optional)
end_session_endpoint: https://your-domain.okta.com/oauth2/default/v1/logout
post_logout_redirect_uri: <%= ENV['VULCAN_APP_URL'] %>
development:
<<: *defaults
production:
<<: *defaults
Additional Security Configurations
1. Implement Proper Logout with Session Cleanup
Create a custom sessions controller to handle both local and Okta session termination:
# app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
def destroy
id_token = session[:id_token]
session.clear
reset_session
if Settings.oidc.enabled && id_token
# Construct Okta logout URL
okta_logout_params = {
id_token_hint: id_token,
post_logout_redirect_uri: root_url
}.to_query
okta_logout_url = "https://#{ENV['VULCAN_OIDC_HOST']}/oauth2/default/v1/logout?#{okta_logout_params}"
redirect_to okta_logout_url, allow_other_host: true
else
super
end
end
end
Update routes to use the custom controller:
# config/routes.rb
devise_for :users, controllers: {
omniauth_callbacks: 'users/omniauth_callbacks',
registrations: 'users/registrations',
sessions: 'sessions'
}
2. Store ID Token for Logout
Modify the OmniAuth callback to store the ID token:
# app/controllers/users/omniauth_callbacks_controller.rb
def oidc
auth = request.env['omniauth.auth']
user = User.from_omniauth(auth)
# Store ID token for logout
session[:id_token] = auth.credentials.id_token if auth.credentials.id_token
flash.notice = I18n.t('devise.sessions.signed_in')
sign_in_and_redirect(user)
end
3. Add CSRF Protection for OmniAuth
Ensure CSRF protection is properly configured:
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
# This handles CSRF protection
provider :developer unless Rails.env.production?
end
# Ensure omniauth-rails_csrf_protection gem is in Gemfile
4. Configure Session Security
Add session security settings:
# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store,
key: '_vulcan_session',
secure: Rails.env.production?, # HTTPS only in production
httponly: true,
same_site: :lax # Prevents CSRF attacks
Troubleshooting
Users not prompted for 2FA
- Add
prompt: 'login'
to force re-authentication - Clear browser cookies for both your app and Okta domains
- Ensure Okta policies require 2FA for the application
- Check Okta's session lifetime settings (shorter = more frequent 2FA)
"Invalid Credentials" Error
- Verify all environment variables are set correctly
- Ensure you're using the correct authorization server (
/oauth2/default
or custom) - Check that redirect URI matches exactly (protocol, domain, path)
- Verify client ID and secret are correct
Login redirect issues
- Verify the redirect URI matches exactly (including trailing slashes)
- Check that VULCAN_APP_URL is set correctly and includes protocol (https://)
- Ensure HTTPS is used in production
- Add redirect URI to Okta app's allowed list
Session timeout issues
- Check
Settings.local_login.session_timeout
configuration - Verify Devise
:timeoutable
is configured properly - Consider Okta session lifetime settings
- Implement activity-based session extension if needed
CSRF Token Errors
- Ensure
omniauth-rails_csrf_protection
gem is installed - Verify
protect_from_forgery
is enabled in ApplicationController - Check that session cookies are properly configured
Best Practices
-
Use Discovery Endpoint: Consider using OIDC discovery for automatic configuration:
# In vulcan.yml discovery: true issuer: https://your-domain.okta.com/oauth2/default
-
Monitor Auth Logs: Enable detailed logging in development:
# config/initializers/omniauth.rb OmniAuth.config.logger = Rails.logger if Rails.env.development?
-
Handle Auth Failures Gracefully:
# app/controllers/application_controller.rb def after_sign_in_path_for(resource) stored_location_for(resource) || projects_path end def after_sign_out_path_for(resource_or_scope) new_user_session_path end
-
Test Integration Thoroughly:
- Test login flow with 2FA enabled
- Test logout from both app and Okta
- Test session timeout behavior
- Test with multiple browser tabs