advanced-manufacturing-techniques
Applying the Abstract Factory Pattern to Support Multiple Authentication Protocols in Oauth Implementations
Table of Contents
The OAuth 2.0 framework has become the de facto standard for delegated authorization, enabling third‑party applications to access user resources without exposing credentials. As organizations expand their digital ecosystems, they often need to support multiple authentication protocols — such as OpenID Connect, SAML 2.0, and LDAP — to accommodate varying security requirements, legacy systems, and user preferences. Designing an authentication system that can handle these diverse protocols in a clean, maintainable, and extensible way is a significant architectural challenge. The Abstract Factory pattern, a classic creational design pattern from the Gang of Four, offers a robust solution. By decoupling the creation of protocol‑specific objects from the core OAuth logic, the Abstract Factory pattern allows developers to introduce new authentication methods with minimal disruption. This article explores how to apply the Abstract Factory pattern to manage multiple authentication protocols within an OAuth implementation, providing a flexible foundation that can scale with your application’s needs.
Understanding the Abstract Factory Pattern
The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. It is particularly useful when a system needs to be independent of how its objects are created, composed, and represented. In the classic terminology, an Abstract Factory declares a set of creation methods, each returning an abstract product. Concrete Factories implement these methods to produce specific product variants. The Client uses only the abstract factory and abstract product interfaces, never dealing with concrete implementations directly.
For example, consider a GUI toolkit that can render widgets for different operating systems. An AbstractWidgetFactory might declare createButton() and createCheckbox(). A WindowsFactory would return Windows‑style buttons and checkboxes, while a MacFactory would produce Mac‑styled versions. The client code works with the abstract factory and sees only Button and Checkbox interfaces, remaining completely agnostic to the underlying platform. This same principle maps beautifully onto authentication protocols.
The Challenge of Multiple Authentication Protocols in OAuth
OAuth 2.0 specifies a set of flows (authorization code, implicit, client credentials, etc.) that enable secure delegation. However, the protocol does not dictate authentication — it focuses on authorization. To authenticate users, organizations layer additional protocols on top of OAuth. Common examples include:
- OpenID Connect (OIDC): An identity layer built on OAuth 2.0 that provides ID tokens (JWTs), userinfo endpoints, and standardised claims. It is the modern choice for web and mobile SSO.
- SAML 2.0: An XML‑based protocol often used in enterprise environments for federated identity. SAML assertions are exchanged between identity providers (IdPs) and service providers (SPs). While not natively part of OAuth, SAML can be integrated as an authentication mechanism.
- LDAP: A directory service protocol frequently used for internal user stores. In an OAuth context, LDAP can serve as the source of truth for validating user credentials and retrieving attributes.
Each of these protocols has its own object model, validation rules, token formats, and session management strategies. A naive implementation that hard‑codes protocol‑specific logic quickly becomes brittle. Adding support for a new authentication protocol would require modifying core OAuth components, increasing the risk of regression and reducing maintainability. The Abstract Factory pattern addresses this by isolating the creation of protocol‑specific objects, allowing the main OAuth flow to remain protocol‑independent.
Applying the Abstract Factory Pattern to OAuth Implementations
Defining the Abstract Factory and Product Interfaces
The first step is to identify the objects that vary across authentication protocols. In a typical OAuth implementation, the following responsibilities are protocol‑dependent:
- Token Validation: Validating access tokens, ID tokens, or SAML assertions.
- User Info Retrieval: Fetching user attributes from a userinfo endpoint, a SAML AttributeStatement, or an LDAP directory.
- Session Management: Creating, updating, and destroying sessions according to the protocol’s semantics.
- Authorization Request Generation: Building the initial authorization request (OAuth parameters, SAML AuthnRequest, or LDAP bind request).
We define abstract product interfaces for each of these responsibilities:
interface TokenValidator {
function validate($token): TokenResult;
}
interface UserInfoFetcher {
function fetchUserInfo($token): User;
}
interface SessionManager {
function createSession($user): Session;
function destroySession($sessionId): void;
}
Next, we declare an abstract factory interface that declares creation methods for each product:
interface AuthProtocolFactory {
function createTokenValidator(): TokenValidator;
function createUserInfoFetcher(): UserInfoFetcher;
function createSessionManager(): SessionManager;
}
Implementing Concrete Factories for Each Protocol
For each authentication protocol, we implement a concrete factory and corresponding concrete products. For example, an OIDC Factory might look like:
class OIDC_TokenValidator implements TokenValidator { /* JWt validation, aud check, etc. */ }
class OIDC_UserInfoFetcher implements UserInfoFetcher { /* call userinfo endpoint */ }
class OIDC_SessionManager implements SessionManager { /* use ID token claims to start session */ }
class OpenIDConnectFactory implements AuthProtocolFactory {
public function createTokenValidator(): TokenValidator { return new OIDC_TokenValidator(); }
public function createUserInfoFetcher(): UserInfoFetcher { return new OIDC_UserInfoFetcher(); }
public function createSessionManager(): SessionManager { return new OIDC_SessionManager(); }
}
Similarly, a SAML Factory would produce objects that decode SAML assertions, extract attributes, and manage sessions based on NameID and session indexes. An LDAP Factory would validate credentials via a bind, retrieve user entries, and create sessions from directory attributes. Each concrete factory encapsulates all the details of its protocol, ensuring that no protocol‑specific logic leaks into the core OAuth flow.
Integrating the Factory into the OAuth Flow
The client (typically the OAuth authorization server or a middleware component) receives a configuration that indicates which authentication protocol is active for a given request (e.g., based on client registration, domain, or user preference). It then instantiates the appropriate concrete factory at runtime, often using a simple factory method or a dependency injection container. The client never references concrete classes directly; it works only with the abstract factory and product interfaces.
// Example client code (simplified)
function handleAuthRequest(string $protocol): void {
$factory = FactoryRegistry::getFactory($protocol); // returns AuthProtocolFactory
$tokenValidator = $factory->createTokenValidator();
$userInfoFetcher = $factory->createUserInfoFetcher();
$sessionManager = $factory->createSessionManager();
$tokenResult = $tokenValidator->validate($requestToken);
if ($tokenResult->isValid()) {
$user = $userInfoFetcher->fetchUserInfo($tokenResult->getAccessToken());
$session = $sessionManager->createSession($user);
// proceed with OAuth token generation, etc.
}
}
This design allows the core OAuth logic to remain unchanged when a new authentication protocol is introduced. Developers simply write a new concrete factory and the associated product classes, then register the factory in the registry.
Real‑World Example: Supporting OIDC and SAML in a Headless CMS
Consider a headless CMS like Directus that needs to support both OIDC‑based SSO (for modern web applications) and SAML‑based SSO (for enterprise customers using Active Directory Federation Services). The existing Directus authentication system can be extended using the Abstract Factory pattern. The core OAuth authorization server remains protocol‑agnostic. An SSOFactoryRegistry is configured via environment variables or the admin panel. When a user lands on the login page and selects “Log in with SAML”, the system retrieves the SAML factory, which creates a SAML_AuthnRequestBuilder, a SAML_AssertionValidator, and a SAML_SessionManager. The OAuth flow calls these interchangeable components without ever knowing they are SAML‑specific. When a new protocol emerges (e.g., WebAuthn or a proprietary OTP scheme), a developer can implement a new factory and plug it in without touching the core authentication logic. Directus authentication documentation provides a starting point for understanding how such a pattern might be integrated.
Benefits of Using the Abstract Factory Pattern
- Flexibility: Adding support for a new authentication protocol is as simple as implementing a new concrete factory and its products. No existing code needs to be modified, reducing the risk of introducing bugs.
- Maintainability: Protocol‑specific code is encapsulated in separate classes, making the overall system easier to understand, test, and debug. Changes to one protocol’s implementation do not cascade to others.
- Scalability: Multiple protocols can coexist in the same deployment. The factory registry can be populated dynamically based on client configuration, supporting multi‑tenant SaaS applications with distinct authentication requirements.
- Consistency: All factories produce products that adhere to the same interfaces, ensuring a uniform interaction pattern. This consistency simplifies logging, auditing, and error handling across protocols.
- Testability: The abstract interfaces make it straightforward to create mock factories or test doubles for unit testing the core OAuth flow without requiring an actual OIDC or SAML environment.
Considerations and Best Practices
Dependency Injection and Configuration
Abstract factories are most effective when combined with a dependency injection container. The factory registry can be populated at application startup based on configuration files, environment variables, or database entries. This decouples the selection of the factory from the code that uses it, allowing runtime hot‑switching (e.g., per client, per tenant).
Handling Protocol Overlaps
Some protocols share common functionality. For example, both OIDC and SAML may need to validate JSON Web Tokens or X.509 certificates. In these cases, consider composing the concrete factories with shared utilities rather than duplicating code. The Abstract Factory pattern does not prevent using helper classes or base product implementations — it only mandates that the client interacts through abstract interfaces.
Performance Considerations
The overhead of using an abstract factory is negligible. Object creation is a small fraction of the overall request, especially when compared to network calls to identity providers. However, if object creation is expensive (e.g., loading certificate chains), you may incorporate caching within the concrete factory or use a pooling strategy.
Licensing and External Libraries
Many authentication protocols have mature open‑source libraries. For example, league/oauth2-server provides a solid OAuth 2.0 foundation, while onelogin/php-saml handles SAML assertions. The Abstract Factory pattern can wrap these libraries, insulating your application from changes in third‑party APIs. If a library updates, only the corresponding concrete factory needs adjustment.
Conclusion
The Abstract Factory pattern offers a proven, architectural approach to managing multiple authentication protocols within OAuth implementations. By abstracting the creation of protocol‑specific objects — such as token validators, user info fetchers, and session managers — developers can build authentication systems that are flexible, maintainable, and ready for future identity standards. Whether your application needs to support OpenID Connect for a modern mobile app, SAML for an enterprise customer, or LDAP for an internal tool, the Abstract Factory pattern provides a clean separation of concerns that keeps your core OAuth flow robust and protocol‑agnostic.
Incorporating this pattern early in the design of an authentication module saves significant effort down the road. As new authentication protocols emerge or as existing ones evolve, you simply add new factories and products — no invasive refactoring required. For any team building or extending an OAuth‑based system, applying the Abstract Factory pattern is a strategic investment in the longevity and adaptability of the authentication infrastructure. Learn more about the Abstract Factory pattern and consider how it can simplify your next OAuth integration.