diff --git a/src/main/java/org/fireflyframework/idp/adapter/IdpAdapter.java b/src/main/java/org/fireflyframework/idp/adapter/IdpAdapter.java
index 76ebfae..e6cd03e 100644
--- a/src/main/java/org/fireflyframework/idp/adapter/IdpAdapter.java
+++ b/src/main/java/org/fireflyframework/idp/adapter/IdpAdapter.java
@@ -17,186 +17,39 @@
package org.fireflyframework.idp.adapter;
-import org.fireflyframework.idp.dtos.*;
+import org.fireflyframework.idp.dtos.CreateUserRequest;
+import org.fireflyframework.idp.dtos.CreateUserResponse;
+import org.fireflyframework.idp.dtos.RegisterUserRequest;
+import org.fireflyframework.idp.port.AuthenticationPort;
+import org.fireflyframework.idp.port.MfaPort;
+import org.fireflyframework.idp.port.RoleScopePort;
+import org.fireflyframework.idp.port.SessionPort;
+import org.fireflyframework.idp.port.TokenIntrospectionPort;
+import org.fireflyframework.idp.port.UserAdminPort;
import org.springframework.http.ResponseEntity;
import reactor.core.publisher.Mono;
-import java.util.List;
-
/**
- * Identity Provider (IdP) adapter interface that standardizes common authentication and
- * user‑management operations across different IdPs such as Keycloak, AWS Cognito, Okta, etc.
+ * Identity Provider (IdP) adapter — the aggregate of the segregated capability ports
+ * ({@link AuthenticationPort}, {@link TokenIntrospectionPort}, {@link UserAdminPort},
+ * {@link RoleScopePort}, {@link SessionPort}, {@link MfaPort}) that standardizes authentication and
+ * user-management across IdPs such as Keycloak, AWS Cognito, and Entra ID.
*
- * Implementations should translate these generic operations into the specific API calls of the
- * target provider while keeping a consistent, reactive API based on Reactor's Mono.
+ *
Because every capability-port method has a {@code NotSupported} default, an adapter may
+ * implement this aggregate and override only the operations its provider supports, or implement a
+ * single focused port directly. This keeps providers from stubbing capabilities they cannot perform
+ * (the previous fat-interface ISP violation).
*/
-public interface IdpAdapter {
-
- /**
- * Authenticate a user and obtain tokens.
- *
- * Typical mapping is an OAuth2/OIDC token endpoint using Resource Owner Password Credentials,
- * or any custom username/password flow supported by the provider.
- *
- * @param request credentials and client details for the login attempt
- * @return a reactive publisher yielding a ResponseEntity with a TokenResponse on success
- */
- Mono> login(LoginRequest request);
-
- /**
- * Refresh the access token using a refresh token.
- *
- * @param request refresh token and (optionally) client info
- * @return a reactive publisher with a ResponseEntity containing a new TokenResponse
- */
- Mono> refresh(RefreshRequest request);
-
- /**
- * Invalidate tokens or perform a provider-specific logout.
- *
- * Implementations may call the IdP's logout or token revocation endpoint.
- *
- * @param request contains accessToken and refreshToken to invalidate
- */
- Mono logout(LogoutRequest request);
-
- /**
- * Introspect an access token to verify its activity and claims (RFC 7662).
- *
- * @param accessToken the token to introspect
- * @return a reactive publisher with a ResponseEntity containing introspection details
- */
- Mono> introspect(String accessToken);
-
- /**
- * Retrieve OpenID Connect user info associated with the provided access token.
- *
- * @param accessToken a valid access token
- * @return a reactive publisher with a ResponseEntity containing user info claims
- */
- Mono> getUserInfo(String accessToken);
-
- /**
- * Create a new user at the identity provider.
- *
- * @param request details required to create the user (username, email, etc.)
- * @return a reactive publisher with a ResponseEntity containing the created user's summary
- */
- Mono> createUser(CreateUserRequest request);
-
- /**
- * Change a user's password.
- *
- * Implementations should enforce provider-specific requirements (e.g., old password check).
- *
- * @param request contains user identifier and new/old passwords
- */
- Mono changePassword(ChangePasswordRequest request);
-
- /**
- * Trigger a password reset for a given username (e.g., send reset email/SMS).
- *
- * @param username the username (or login identifier) for which to initiate reset
- */
- Mono resetPassword(String username);
-
- /**
- * Initiate a Multi‑Factor Authentication (MFA) challenge for a user.
- *
- * @param username the username to challenge
- * @return a reactive publisher with challenge details (delivery method, expiry, etc.)
- */
- Mono> mfaChallenge(String username);
-
- /**
- * Verify a previously initiated MFA challenge with the supplied code.
- *
- * @param request verification payload including challenge id and code
- */
- Mono mfaVerify(MfaVerifyRequest request);
-
- /**
- * Revoke an issued refresh token.
- *
- * @param refreshToken the refresh token to revoke
- */
- Mono revokeRefreshToken(String refreshToken);
-
- /**
- * List active sessions for a given user.
- *
- * @param userId the user identifier
- * @return a reactive publisher with a list of session information
- */
- Mono>> listSessions(String userId);
-
- /**
- * Revoke a specific session by its identifier.
- *
- * @param sessionId the session identifier to revoke
- */
- Mono revokeSession(String sessionId);
-
- /**
- * Retrieve the roles assigned to a user.
- *
- * @param userId the user identifier
- * @return a reactive publisher with the list of role names
- */
- Mono>> getRoles(String userId);
-
- /**
- * Delete a user by its identifier in the IdP.
- *
- * @param userId the provider-specific user id
- */
- Mono deleteUser(String userId);
-
- /**
- * Update an existing user. Fields left null in the request should not be modified.
- *
- * @param request details to update and user identifier
- * @return a reactive publisher with a summary of the updated user
- */
- Mono> updateUser(UpdateUserRequest request);
-
- /**
- * Create one or more roles at the IdP (realm or client depending on context).
- *
- * @param request role names (and optional context/description)
- * @return a reactive publisher with the list of created role names
- */
- Mono> createRoles(CreateRolesRequest request);
-
- /**
- * Create a new scope (e.g., OAuth2 scope or Keycloak client scope).
- *
- * @param request scope name (and optional context/description)
- * @return a reactive publisher with created scope information
- */
- Mono> createScope(CreateScopeRequest request);
-
- /**
- * Assign roles to a user.
- *
- * @param request user id and role names to assign
- */
- Mono assignRolesToUser(AssignRolesRequest request);
-
- /**
- * Remove roles from a user.
- *
- * @param request user id and role names to remove
- */
- Mono removeRolesFromUser(AssignRolesRequest request);
+public interface IdpAdapter
+ extends AuthenticationPort, TokenIntrospectionPort, UserAdminPort, RoleScopePort, SessionPort, MfaPort {
/**
* Register a new user via self-service (public, no admin auth required).
*
* The default implementation converts the registration request into a
- * {@link CreateUserRequest} and delegates to {@link #createUser(CreateUserRequest)}.
+ * {@link CreateUserRequest} and delegates to {@link UserAdminPort#createUser(CreateUserRequest)}.
* Adapters may override this to use provider-specific self-service APIs
- * (e.g., Cognito {@code SignUp}, Keycloak self-registration).
+ * (e.g. Cognito {@code SignUp}, Keycloak self-registration).
*
* @param request the self-service registration details
* @return a reactive publisher with the created user's summary
diff --git a/src/main/java/org/fireflyframework/idp/dtos/CreateUserRequest.java b/src/main/java/org/fireflyframework/idp/dtos/CreateUserRequest.java
index fc0c0e5..1efe23e 100644
--- a/src/main/java/org/fireflyframework/idp/dtos/CreateUserRequest.java
+++ b/src/main/java/org/fireflyframework/idp/dtos/CreateUserRequest.java
@@ -17,15 +17,18 @@
package org.fireflyframework.idp.dtos;
-import org.fireflyframework.idp.dtos.enums.UserRoleEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
-import java.util.UUID;
+/**
+ * Vendor-neutral request to provision a user. Product-specific identity attributes (e.g. a party
+ * or contract reference) are carried generically in {@link #attributes} — the framework defines no
+ * product domain of its own.
+ */
@Data
@Builder
@NoArgsConstructor
@@ -36,7 +39,5 @@ public class CreateUserRequest {
private String password;
private String givenName;
private String familyName;
- private UUID partyId;
- private UserRoleEnum userRole;
private Map attributes;
}
diff --git a/src/main/java/org/fireflyframework/idp/dtos/IntrospectionResponse.java b/src/main/java/org/fireflyframework/idp/dtos/IntrospectionResponse.java
index aa01ffd..c5e4df3 100644
--- a/src/main/java/org/fireflyframework/idp/dtos/IntrospectionResponse.java
+++ b/src/main/java/org/fireflyframework/idp/dtos/IntrospectionResponse.java
@@ -18,15 +18,18 @@
package org.fireflyframework.idp.dtos;
import com.fasterxml.jackson.annotation.JsonFormat;
-import org.fireflyframework.idp.dtos.enums.UserRoleEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
-import java.util.UUID;
+import java.util.Map;
+/**
+ * RFC 7662 token introspection response. Product-specific claims are returned generically in
+ * {@link #attributes}; the framework keeps no product domain (no party, contract, or business role).
+ */
@Data
@Builder
@NoArgsConstructor
@@ -42,6 +45,5 @@ public class IntrospectionResponse {
private List aud;
private String iss;
private String jti;
- private UUID partyId;
- private UserRoleEnum userRole;
+ private Map attributes;
}
diff --git a/src/main/java/org/fireflyframework/idp/dtos/enums/UserRoleEnum.java b/src/main/java/org/fireflyframework/idp/dtos/enums/UserRoleEnum.java
deleted file mode 100644
index 464bf60..0000000
--- a/src/main/java/org/fireflyframework/idp/dtos/enums/UserRoleEnum.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.fireflyframework.idp.dtos.enums;
-
-public enum UserRoleEnum {
- AGENT,
- SUPER_AGENT,
- DISTRIBUTOR,
- ADMIN
-}
diff --git a/src/main/java/org/fireflyframework/idp/port/AuthenticationPort.java b/src/main/java/org/fireflyframework/idp/port/AuthenticationPort.java
new file mode 100644
index 0000000..14de044
--- /dev/null
+++ b/src/main/java/org/fireflyframework/idp/port/AuthenticationPort.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2024-2026 Firefly Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fireflyframework.idp.port;
+
+import org.fireflyframework.idp.dtos.LoginRequest;
+import org.fireflyframework.idp.dtos.LogoutRequest;
+import org.fireflyframework.idp.dtos.RefreshRequest;
+import org.fireflyframework.idp.dtos.TokenResponse;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+/**
+ * Segregated IdP capability port for authentication / token-lifecycle operations.
+ *
+ * Each method has a {@code NotSupported} default so an adapter implements only the capabilities
+ * its provider actually offers, instead of stubbing the rest. The aggregate {@code IdpAdapter}
+ * composes this with the other capability ports.
+ */
+public interface AuthenticationPort {
+
+ default Mono> login(LoginRequest request) {
+ return Mono.error(new UnsupportedOperationException("login is not supported by this IdP provider"));
+ }
+
+ default Mono> refresh(RefreshRequest request) {
+ return Mono.error(new UnsupportedOperationException("refresh is not supported by this IdP provider"));
+ }
+
+ default Mono logout(LogoutRequest request) {
+ return Mono.error(new UnsupportedOperationException("logout is not supported by this IdP provider"));
+ }
+}
diff --git a/src/main/java/org/fireflyframework/idp/port/MfaPort.java b/src/main/java/org/fireflyframework/idp/port/MfaPort.java
new file mode 100644
index 0000000..1e43793
--- /dev/null
+++ b/src/main/java/org/fireflyframework/idp/port/MfaPort.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024-2026 Firefly Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fireflyframework.idp.port;
+
+import org.fireflyframework.idp.dtos.MfaChallengeResponse;
+import org.fireflyframework.idp.dtos.MfaVerifyRequest;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+/**
+ * Segregated IdP capability port for multi-factor authentication challenge/verify.
+ */
+public interface MfaPort {
+
+ default Mono> mfaChallenge(String username) {
+ return Mono.error(new UnsupportedOperationException("mfaChallenge is not supported by this IdP provider"));
+ }
+
+ default Mono mfaVerify(MfaVerifyRequest request) {
+ return Mono.error(new UnsupportedOperationException("mfaVerify is not supported by this IdP provider"));
+ }
+}
diff --git a/src/main/java/org/fireflyframework/idp/port/RoleScopePort.java b/src/main/java/org/fireflyframework/idp/port/RoleScopePort.java
new file mode 100644
index 0000000..e1b4a5a
--- /dev/null
+++ b/src/main/java/org/fireflyframework/idp/port/RoleScopePort.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2024-2026 Firefly Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fireflyframework.idp.port;
+
+import org.fireflyframework.idp.dtos.AssignRolesRequest;
+import org.fireflyframework.idp.dtos.CreateRolesRequest;
+import org.fireflyframework.idp.dtos.CreateRolesResponse;
+import org.fireflyframework.idp.dtos.CreateScopeRequest;
+import org.fireflyframework.idp.dtos.CreateScopeResponse;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+/**
+ * Segregated IdP capability port for role and scope management and role assignment.
+ */
+public interface RoleScopePort {
+
+ default Mono>> getRoles(String userId) {
+ return Mono.error(new UnsupportedOperationException("getRoles is not supported by this IdP provider"));
+ }
+
+ default Mono> createRoles(CreateRolesRequest request) {
+ return Mono.error(new UnsupportedOperationException("createRoles is not supported by this IdP provider"));
+ }
+
+ default Mono> createScope(CreateScopeRequest request) {
+ return Mono.error(new UnsupportedOperationException("createScope is not supported by this IdP provider"));
+ }
+
+ default Mono assignRolesToUser(AssignRolesRequest request) {
+ return Mono.error(new UnsupportedOperationException("assignRolesToUser is not supported by this IdP provider"));
+ }
+
+ default Mono removeRolesFromUser(AssignRolesRequest request) {
+ return Mono.error(new UnsupportedOperationException("removeRolesFromUser is not supported by this IdP provider"));
+ }
+}
diff --git a/src/main/java/org/fireflyframework/idp/port/SessionPort.java b/src/main/java/org/fireflyframework/idp/port/SessionPort.java
new file mode 100644
index 0000000..5cf2038
--- /dev/null
+++ b/src/main/java/org/fireflyframework/idp/port/SessionPort.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2024-2026 Firefly Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fireflyframework.idp.port;
+
+import org.fireflyframework.idp.dtos.SessionInfo;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+/**
+ * Segregated IdP capability port for session and refresh-token lifecycle management.
+ */
+public interface SessionPort {
+
+ default Mono revokeRefreshToken(String refreshToken) {
+ return Mono.error(new UnsupportedOperationException("revokeRefreshToken is not supported by this IdP provider"));
+ }
+
+ default Mono>> listSessions(String userId) {
+ return Mono.error(new UnsupportedOperationException("listSessions is not supported by this IdP provider"));
+ }
+
+ default Mono revokeSession(String sessionId) {
+ return Mono.error(new UnsupportedOperationException("revokeSession is not supported by this IdP provider"));
+ }
+}
diff --git a/src/main/java/org/fireflyframework/idp/port/TokenIntrospectionPort.java b/src/main/java/org/fireflyframework/idp/port/TokenIntrospectionPort.java
new file mode 100644
index 0000000..23d79be
--- /dev/null
+++ b/src/main/java/org/fireflyframework/idp/port/TokenIntrospectionPort.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024-2026 Firefly Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fireflyframework.idp.port;
+
+import org.fireflyframework.idp.dtos.IntrospectionResponse;
+import org.fireflyframework.idp.dtos.UserInfoResponse;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+/**
+ * Segregated IdP capability port for token introspection (RFC 7662) and OIDC userinfo. This is the
+ * provider-facing source behind the security tier's opaque-token validation path.
+ */
+public interface TokenIntrospectionPort {
+
+ default Mono> introspect(String accessToken) {
+ return Mono.error(new UnsupportedOperationException("introspect is not supported by this IdP provider"));
+ }
+
+ default Mono> getUserInfo(String accessToken) {
+ return Mono.error(new UnsupportedOperationException("getUserInfo is not supported by this IdP provider"));
+ }
+}
diff --git a/src/main/java/org/fireflyframework/idp/port/UserAdminPort.java b/src/main/java/org/fireflyframework/idp/port/UserAdminPort.java
new file mode 100644
index 0000000..4030293
--- /dev/null
+++ b/src/main/java/org/fireflyframework/idp/port/UserAdminPort.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024-2026 Firefly Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.fireflyframework.idp.port;
+
+import org.fireflyframework.idp.dtos.ChangePasswordRequest;
+import org.fireflyframework.idp.dtos.CreateUserRequest;
+import org.fireflyframework.idp.dtos.CreateUserResponse;
+import org.fireflyframework.idp.dtos.UpdateUserRequest;
+import org.fireflyframework.idp.dtos.UpdateUserResponse;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+/**
+ * Segregated IdP capability port for user administration (CRUD + password operations).
+ */
+public interface UserAdminPort {
+
+ default Mono> createUser(CreateUserRequest request) {
+ return Mono.error(new UnsupportedOperationException("createUser is not supported by this IdP provider"));
+ }
+
+ default Mono changePassword(ChangePasswordRequest request) {
+ return Mono.error(new UnsupportedOperationException("changePassword is not supported by this IdP provider"));
+ }
+
+ default Mono resetPassword(String username) {
+ return Mono.error(new UnsupportedOperationException("resetPassword is not supported by this IdP provider"));
+ }
+
+ default Mono deleteUser(String userId) {
+ return Mono.error(new UnsupportedOperationException("deleteUser is not supported by this IdP provider"));
+ }
+
+ default Mono> updateUser(UpdateUserRequest request) {
+ return Mono.error(new UnsupportedOperationException("updateUser is not supported by this IdP provider"));
+ }
+}