-
Notifications
You must be signed in to change notification settings - Fork 730
Description
Description
Summary
This proposal enhances AdminJS's authentication architecture to natively support multiple, heterogeneous authentication providers (Default, OAuth, SSO, etc.) configured simultaneously. This requires an update to AuthenticationOptions and the introduction of provider-aware session tracking.
Suggested Solution
1. Configuration Changes (AuthenticationOptions)
The existing AuthenticationOptions must be updated to support a map of providers, replacing the single provider property.
Proposed New AuthenticationOptions
The updated type should introduce a new property, providers, to hold a map of all available authentication strategies, and deprecate the single-function authenticate and single provider properties for the multi-auth use case.
export type AuthenticationOptions = {
cookiePassword: string;
cookieName?: string;
/**
* @deprecated Use the 'providers' map instead, with one provider having type 'default'.
*/
authenticate?: (email: string, password: string, context?: AuthenticationContext) => unknown | null;
/**
* @deprecated Use the 'providers' map instead.
*/
provider?: BaseAuthProvider;
/**
* New property: A map of unique keys to BaseAuthProvider instances.
* Required for multi-provider support (OAuth, SSO, Default combined).
*/
providers: {
[key: string]: BaseAuthProvider; // Key is used as providerId for session tracking
};
/**
* @description Maximum number of authorization attempts (if number - per minute)
*/
maxRetries?: number | AuthenticationMaxRetriesOptions;
};2. Provider Interface Enhancements (BaseAuthProvider)
The provider interface needs a new method to communicate UI requirements to the AdminJS frontend.
interface LoginProviderUiProps {
providerId: string;
// Defines how the frontend should interact with this provider
// 'default' means the authenticate already changed as DefaultAuthProvider
type: 'default' | 'oauth' | 'sso' ;
displayName: string;
buttonIcon?: string;
/**
* EXTENSION: An optional payload for passing provider-specific configuration
* needed by a custom or overridden frontend component.
* For example, a Firebase provider might pass 'firebaseConfig' here.
*/
payload?: Record<string, any>;
}
// Example usage by a hypothetical FirebaseAuthProvider
export class Keycloak extends BaseAuthProvider {
// ... constructor takes custom keycloak config
public getUiProps(): LoginProviderUiProps {
const { keycloakUrl, realm, clientId, adminJsUrl, loginPath } = this.keycloakConfig;
const redirectUri = `${adminJsUrl}${loginPath}`;
const authUrl =
`${keycloakUrl}/realms/${realm}/protocol/openid-connect/auth?` +
`client_id=${clientId}&` +
`redirect_uri=${encodeURIComponent(redirectUri)}&` +
`response_type=code&` +
`scope=openid profile email`;
return {
providerId: 'keycloak',
type: 'oauth',
displayName: 'Sign in with Keycloak,
buttonIcon: `fa-key`
// Passing custom details for the frontend component
payload: {
authUrl,
}
};
}
}3. Dynamic UI and Session Management
Frontend Behavior (Login Page)
The AdminJS core aggregates the UI props by iterating over the configured providers map and calling provider.getUiProps().
The default Login Component consumes this list and renders elements dynamically:
- It renders the full login form for the provider with
type: 'default'. - It renders clickable buttons (e.g., "Sign in with Google") for providers with
type: 'oauth'ortype: 'sso', linking directly to the respective loginPath. - Use hooks to update currentAdmin provider id.
Backend Session Tracking
- Login Success: When any provider's
handleLoginmethod successfully returns a user object, the AdminJS core must inject the provider's key into the CurrentAdmin object before saving it to the session.
interface CurrentAdmin {
// ... user data
providerId: string; // New mandatory field to track authentication source
}- Session Actions (Logout/Refresh): For actions like logging out, the AdminJS core will retrieve the providerId from the active CurrentAdmin and delegate the session termination (handleLogout) or refresh (handleRefreshToken) to that specific provider instance. This ensures external sessions (e.g., at an IdP) are also properly managed.
Alternatives
No response
Additional Context
No response