OAuth SSO Implementation Plan for Google/GitHub Logins

Executive Summary

Wikantik's JAAS-based architecture is well-suited for OAuth integration. The key insight is that passwords are optional in the user database, so OAuth users can be created without passwords and never use password-based login.


Required Components

1. 1. New Java Classes (~6-8 files)
FilePurpose
OAuthLoginModule.javaJAAS LoginModule that validates tokens and creates/links users
OAuthCallbackHandler.javaPasses OAuth token to LoginModule via JAAS callbacks
OAuthCallback.javaCustom JAAS Callback for OAuth data
OAuthCallbackServlet.javaHandles /wiki/oauth/callback redirect from providers
GoogleOAuthProvider.javaValidates Google tokens, fetches user info
GitHubOAuthProvider.javaValidates GitHub tokens, fetches user info
OAuthUserInfo.javaDTO for user info from providers
1. 2. UI Modifications
# OAuth SSO Configuration
jspwiki.oauth.enabled=true
jspwiki.oauth.autoCreateUsers=true

# Google OAuth 2.0 / OpenID Connect
jspwiki.oauth.google.enabled=true
jspwiki.oauth.google.clientId=YOUR_CLIENT_ID
jspwiki.oauth.google.clientSecret=YOUR_CLIENT_SECRET

# GitHub OAuth 2.0
jspwiki.oauth.github.enabled=true
jspwiki.oauth.github.clientId=YOUR_CLIENT_ID
jspwiki.oauth.github.clientSecret=YOUR_CLIENT_SECRET
1. 4. Dependencies (pom.xml)

OAuth Flow Integration

# User clicks "Login with Google" on LoginContent.jsp
                    ↓
2. OAuthCallbackServlet redirects to Google consent screen
                    ↓
3. User authenticates with Google
                    ↓
4. Google redirects to /wiki/oauth/callback?code=...&state=...
                    ↓
5. OAuthCallbackServlet:
   - Exchanges code for access token
   - Fetches user info (email, name, provider ID)
   - Creates OAuthCallbackHandler with token data
   - Calls AuthenticationManager with OAuthLoginModule
                    ↓
6. OAuthLoginModule.login():
   - Gets token data from callback handler
   - Looks up user by email in UserDatabase
   - If not found: creates new UserProfile (no password)
   - Adds WikiPrincipal to principals set
                    ↓
7. WikiSession.actionPerformed():
   - Receives LOGIN_AUTHENTICATED event
   - Sets session status to AUTHENTICATED
   - Injects user profile principals
   - Injects group memberships
                    ↓
8. Redirect to original page

User Account Creation Strategy

// In OAuthLoginModule.login()
UserProfile profile;
try {
    profile = db.findByEmail(oauthUserInfo.getEmail());
} catch (NoSuchPrincipalException e) {
    // Create new user
    profile = db.newProfile();
    profile.setLoginName(generateLoginName(oauthUserInfo));
    profile.setEmail(oauthUserInfo.getEmail());
    profile.setFullname(oauthUserInfo.getName());
    profile.setPassword(null);  // No password for OAuth users

    // Store OAuth metadata in custom attributes
    profile.getAttributes().put("oauth.provider", "google");
    profile.getAttributes().put("oauth.providerId", oauthUserInfo.getId());

    db.save(profile);
}

Login Name Generation Options


Key Technical Insights

1. 1. Password-less Users Work Out-of-Box

UserDatabaseLoginModule.login() line 86 checks:

if (storedPassword != null && db.validatePassword(...))

OAuth users with null password bypass password validation entirely.

1. 2. Session Establishment is Automatic

Just fire the event and WikiSession handles everything:

fireEvent(WikiSecurityEvent.LOGIN_AUTHENTICATED, principal, session);
1. 3. Configuration is Already Flexible

DefaultAuthenticationManager.initLoginModuleOptions() loads all jspwiki.loginModule.options.* properties and passes them to the LoginModule.

1. 4. User Database Abstraction Works Well

The JDBCUserDatabase supports:


Challenges & Solutions

ChallengeSolution
Same person, multiple providersLink by email; store provider info in attributes
Incomplete profile dataCompute full name from email; prompt for completion
Token expiryStore refresh token (encrypted) in attributes
Logout coordinationClear local session; optionally revoke provider token
Account securityRequire email verification; admin account linking tool

Estimated Effort

PhaseEffortDescription
Core OAuth3-4 daysLoginModule, CallbackHandler, Servlet, Providers
User provisioning1-2 daysAccount creation, email linking, attributes
UI1 dayLogin buttons, styling
Configuration0.5 dayProperties, documentation
Testing2-3 daysUnit tests, integration tests
Total~8-10 daysFor experienced developer

Architecture Decision: Servlet + LoginModule Hybrid

  1. OAuthCallbackServlet handles:

    • OAuth redirect flow
    • Authorization code exchange
    • Token validation
    • Calling provider APIs
  2. OAuthLoginModule handles:

    • User lookup/creation in database
    • Principal establishment
    • JAAS integration

This separation keeps OAuth protocol details out of JAAS and allows the LoginModule to focus on user management.


Files to Modify (Existing)

FileChange
wikantik.propertiesAdd OAuth configuration properties
LoginContent.jspAdd OAuth login buttons
web.xmlRegister OAuthCallbackServlet
pom.xmlAdd OAuth dependencies

Key Code Locations

Authentication Flow

User Management

Login Modules

Configuration

UI


Conclusion

Implementing OAuth SSO for Google/GitHub in Wikantik is architecturally straightforward due to:

  1. Pluggable JAAS LoginModules - No changes to auth framework needed
  2. Optional passwords - OAuth users created without passwords work perfectly
  3. Automatic session setup - Fire event, session handles the rest
  4. Flexible user database - Custom attributes for OAuth metadata

The main work is implementing the OAuth protocol (token exchange, API calls) and user provisioning logic. The Wikantik authentication infrastructure supports this cleanly.