Skip to content

Improve support for multiple / pluggable auth types #88

Description

@taylortom

Summary

Following a review of the auth extensibility mechanism (AbstractAuthModule + the Authentication registry), the plugin seam is well-designed and genuinely pluggable — but there are a few improvements that would make it comfortable to run multiple auth types in production. A prototype Okta plugin was used as the reference for a redirect/OAuth-style implementation.

The extension point itself is strong: a plugin declares a type and need only implement authenticate(user, req, res); everything downstream (JWT generation, sessions, scope resolution, RBAC, route gating) is auth-type-agnostic and inherited. This was validated against two structurally opposite implementations — adapt-authoring-auth-local (credential verification) and the Okta prototype (passport redirect → /callback → token). No changes to the core seam are required for those to work.

The items below are enhancements, not blockers.

Proposed improvements

1. Extract an AbstractOAuthModule to remove per-provider boilerplate

Every OAuth plugin currently re-implements the same scaffolding: passport.initialize()/passport.session(), serializeUser/deserializeUser, the / + /callback routes, unsecureRoute calls, and an onAuthenticated handler that generates the token. The default authenticateHandler is credential-shaped (reads req.body.email/password), so OAuth plugins cannot reuse it and must roll their own.

A second abstract layer (AbstractOAuthModule extends AbstractAuthModule) could own the passport wiring and the callback→token flow, reducing a new provider to: config (client id/secret/callback), a passport strategy, and a mapProfile(profile) → { email, firstName, lastName, roles } mapper.

2. Server-advertised login-method discovery

There is currently no endpoint that tells a client which auth types are enabled or which is the default interactive login method — the client has to know to POST to /api/auth/<type> (or redirect to it). This means two redirect-based providers cannot be cleanly arbitrated: coexistence works fine at the token/API layer, but interactive login effectively assumes a single method.

Proposal: a public GET /api/auth/methods (or similar) that lists registered plugins and flags which are interactive/redirect vs credential-submit, so a client can present a chooser instead of hardcoding a single method.

3. Decide on account linking vs one authType per user

AuthToken.initRequestData resolves the plugin from user.authType, so a user is bound to exactly one auth type. A person provisioned via local cannot also authenticate via an IdP. If SSO and local auth need to serve the same users, this needs an account-linking model; if not, it's worth documenting as an explicit constraint.

Scope

This issue is primarily items 1–3 (enhancements to the extensibility seam). Items 1 and 2 are the highest value. Happy to split into separate issues if preferred.

Metadata

Metadata

Assignees

No one assigned

    Labels

    R&DRequires research/discussionenhancementNew or additional functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions