CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-keycloak--keycloak-server-spi

Service Provider Interface (SPI) contracts and abstractions for the Keycloak identity and access management server enabling extensibility through custom providers

Pending
Overview
Eval results
Files

organization-management.mddocs/

Organization Management

Organization management provides multi-tenant capabilities within Keycloak, allowing for the creation and management of organizations with their own members, identity providers, and domain-based authentication routing. This SPI enables enterprise scenarios where multiple organizations share a single Keycloak realm while maintaining organizational boundaries.

Capabilities

Organization Provider

The primary interface for managing organizations and their associated data within a realm.

/**
 * A Provider that manages organization and its data within the scope of a realm.
 */
public interface OrganizationProvider extends Provider {
    
    /**
     * Creates a new organization with given name and alias to the realm.
     * @param name the name of the organization
     * @param alias the alias of the organization. If not set, defaults to name. Once set, the alias is immutable
     * @throws ModelDuplicateException If there is already an organization with the given name or alias
     * @return Model of the created organization
     */
    OrganizationModel create(String name, String alias);
    
    /**
     * Creates a new organization with given id, name, and alias to the realm
     * @param id the id of the organization
     * @param name the name of the organization
     * @param alias the alias of the organization
     * @throws ModelDuplicateException If there is already an organization with the given name or alias
     * @return Model of the created organization
     */
    OrganizationModel create(String id, String name, String alias);
    
    /**
     * Returns an OrganizationModel by its id
     * @param id the id of an organization
     * @return the organization with the given id or null if there is no such organization
     */
    OrganizationModel getById(String id);
    
    /**
     * Returns an OrganizationModel by its internet domain
     * @param domainName the organization's internet domain (e.g. redhat.com)
     * @return the organization that is linked to the given internet domain
     */
    OrganizationModel getByDomainName(String domainName);
    
    /**
     * Returns an OrganizationModel with the given alias
     * @param alias the alias
     * @return the organization
     */
    OrganizationModel getByAlias(String alias);
    
    /**
     * Returns all organizations in the realm
     * @return a Stream of the realm's organizations
     */
    Stream<OrganizationModel> getAllStream();
    
    /**
     * Returns all organizations in the realm filtered according to the specified parameters
     * @param search a String representing either an organization name or domain
     * @param exact if true, organizations will be searched using exact match
     * @param first the position of the first result to be processed (pagination offset)
     * @param max the maximum number of results to be returned
     * @return a Stream of the matched organizations
     */
    Stream<OrganizationModel> getAllStream(String search, Boolean exact, Integer first, Integer max);
    
    /**
     * Returns all organizations in the realm filtered according to the specified parameters
     * @param attributes a Map containing the attributes (name/value) that must match organization attributes
     * @param first the position of the first result to be processed (pagination offset)
     * @param max the maximum number of results to be returned
     * @return a Stream of the matched organizations
     */
    Stream<OrganizationModel> getAllStream(Map<String, String> attributes, Integer first, Integer max);
    
    /**
     * Removes the given organization from the realm together with the data associated with it
     * @param organization Organization to be removed
     * @throws ModelException if the organization doesn't exist or doesn't belong to the realm
     * @return true if the organization was removed, false otherwise
     */
    boolean remove(OrganizationModel organization);
    
    /**
     * Removes all organizations from the realm
     */
    void removeAll();
    
    /**
     * Returns number of organizations in the realm
     * @return Number of organizations
     */
    long count();
    
    /**
     * Indicates if the current realm supports organization
     * @return true if organization is supported, false otherwise
     */
    boolean isEnabled();
}

Organization Member Management

Comprehensive member management with support for both managed and unmanaged members.

public interface OrganizationProvider extends Provider {
    
    /**
     * Adds the given UserModel as a managed member of the given OrganizationModel.
     * @param organization the organization
     * @param user the user
     * @throws ModelException if the UserModel is member of different organization
     * @return true if the user was added as a member, false otherwise
     */
    boolean addManagedMember(OrganizationModel organization, UserModel user);
    
    /**
     * Adds the given UserModel as an unmanaged member of the given OrganizationModel.
     * @param organization the organization
     * @param user the user
     * @throws ModelException if the UserModel is member of different organization
     * @return true if the user was added as a member, false otherwise
     */
    boolean addMember(OrganizationModel organization, UserModel user);
    
    /**
     * Returns the members of a given OrganizationModel filtered according to the specified filters.
     * @param organization the organization
     * @param filters Map containing filters for member search
     * @param exact if true, exact match for filters
     * @param first the position of the first result (pagination offset)
     * @param max the maximum number of results to be returned
     * @return Stream of the members
     */
    Stream<UserModel> getMembersStream(OrganizationModel organization, Map<String, String> filters, Boolean exact, Integer first, Integer max);
    
    /**
     * Returns number of members in the organization
     * @param organization the organization
     * @return Number of members in the organization
     */
    long getMembersCount(OrganizationModel organization);
    
    /**
     * Returns the member of the OrganizationModel by its id
     * @param organization the organization
     * @param id the member id
     * @return the member of the OrganizationModel with the given id
     */
    UserModel getMemberById(OrganizationModel organization, String id);
    
    /**
     * Returns the OrganizationModel that the member belongs to
     * @param member the member of an organization
     * @return the organizations the member belongs to or an empty stream if the user doesn't belong to any
     */
    Stream<OrganizationModel> getByMember(UserModel member);
    
    /**
     * Indicates if the given member is managed by the organization.
     * A member is managed by the organization whenever the member cannot exist without the organization
     * @param organization the organization
     * @param member the member
     * @return true if the member is managed by the given organization
     */
    boolean isManagedMember(OrganizationModel organization, UserModel member);
    
    /**
     * Indicates if the given user is a member of the given organization
     * @param organization the organization
     * @param user the member
     * @return true if the user is a member, false otherwise
     */
    boolean isMember(OrganizationModel organization, UserModel user);
    
    /**
     * Removes a member from the organization.
     * This method can either remove the given member entirely from the realm or only remove the link to the organization.
     * The decision depends on whether the user is managed by the organization or not.
     * @param organization the organization
     * @param member the member
     * @return true if the given member is a member and was successfully removed from the organization
     */
    boolean removeMember(OrganizationModel organization, UserModel member);
}

Identity Provider Association

Associate identity providers with organizations for automatic user routing and federated authentication.

public interface OrganizationProvider extends Provider {
    
    /**
     * Associate the given IdentityProviderModel with the given OrganizationModel
     * @param organization the organization
     * @param identityProvider the identityProvider
     * @return true if the identityProvider was associated with the organization, false otherwise
     */
    boolean addIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider);
    
    /**
     * Returns Stream of the identity providers associated with the given organization
     * @param organization the organization
     * @return Stream of the identity providers associated with the organization
     */
    Stream<IdentityProviderModel> getIdentityProviders(OrganizationModel organization);
    
    /**
     * Removes the link between the given OrganizationModel and the identity provider if such a link exists
     * @param organization the organization
     * @param identityProvider the identity provider
     * @return true if the link was removed, false otherwise
     */
    boolean removeIdentityProvider(OrganizationModel organization, IdentityProviderModel identityProvider);
}

Organization Model

The core model representing an organization with its attributes, domains, and configuration.

/**
 * Model representation of an organization within a realm.
 */
public interface OrganizationModel {
    
    String ORGANIZATION_ATTRIBUTE = "kc.org";
    String ORGANIZATION_NAME_ATTRIBUTE = "kc.org.name";
    String ORGANIZATION_DOMAIN_ATTRIBUTE = "kc.org.domain";
    String ALIAS = "alias";
    
    /**
     * Identity provider redirect modes for organization-based routing.
     */
    enum IdentityProviderRedirectMode {
        EMAIL_MATCH("kc.org.broker.redirect.mode.email-matches");
        
        private final String key;
        
        IdentityProviderRedirectMode(String key) {
            this.key = key;
        }
        
        public boolean isSet(IdentityProviderModel broker) {
            return Boolean.parseBoolean(broker.getConfig().get(key));
        }
        
        public String getKey() {
            return key;
        }
    }
    
    /**
     * Returns the unique identifier of the organization
     * @return the organization ID
     */
    String getId();
    
    /**
     * Sets the name of the organization
     * @param name the organization name
     */
    void setName(String name);
    
    /**
     * Returns the name of the organization
     * @return the organization name
     */
    String getName();
    
    /**
     * Returns the alias of the organization
     * @return the organization alias
     */
    String getAlias();
    
    /**
     * Sets the alias of the organization
     * @param alias the organization alias
     */
    void setAlias(String alias);
    
    /**
     * Returns whether the organization is enabled
     * @return true if enabled, false otherwise
     */
    boolean isEnabled();
    
    /**
     * Sets whether the organization is enabled
     * @param enabled true to enable, false to disable
     */
    void setEnabled(boolean enabled);
    
    /**
     * Returns the description of the organization
     * @return the organization description
     */
    String getDescription();
    
    /**
     * Sets the description of the organization
     * @param description the organization description
     */
    void setDescription(String description);
    
    /**
     * Returns the redirect URL for the organization
     * @return the redirect URL
     */
    String getRedirectUrl();
    
    /**
     * Sets the redirect URL for the organization
     * @param redirectUrl the redirect URL
     */
    void setRedirectUrl(String redirectUrl);
    
    /**
     * Returns the organization's attributes
     * @return Map of organization attributes
     */
    Map<String, List<String>> getAttributes();
    
    /**
     * Sets the organization's attributes
     * @param attributes Map of organization attributes
     */
    void setAttributes(Map<String, List<String>> attributes);
    
    /**
     * Returns the domains associated with the organization
     * @return Stream of organization domains
     */
    Stream<OrganizationDomainModel> getDomains();
    
    /**
     * Sets the domains associated with the organization
     * @param domains Set of organization domains
     */
    void setDomains(Set<OrganizationDomainModel> domains);
    
    /**
     * Returns the identity providers associated with the organization
     * @return Stream of identity providers
     */
    Stream<IdentityProviderModel> getIdentityProviders();
    
    /**
     * Indicates if the given user is managed by the organization
     * @param user the user
     * @return true if the user is managed by the organization
     */
    boolean isManaged(UserModel user);
    
    /**
     * Indicates if the given user is a member of the organization
     * @param user the user
     * @return true if the user is a member of the organization
     */
    boolean isMember(UserModel user);
}

Organization Domain Model

Model representing internet domains associated with organizations for email-based routing and verification.

/**
 * Model implementation of an organization internet domain.
 */
public class OrganizationDomainModel implements Serializable {
    
    /**
     * Value used to link an identity provider with all domains from the organization.
     * If the user's email domain matches any of the organization domains, automatic redirection will be performed.
     */
    public static final String ANY_DOMAIN = "ANY";
    
    /**
     * Creates a new domain model with the given name (unverified by default)
     * @param name the domain name
     */
    public OrganizationDomainModel(String name);
    
    /**
     * Creates a new domain model with the given name and verification status
     * @param name the domain name
     * @param verified whether the domain is verified
     */
    public OrganizationDomainModel(String name, boolean verified);
    
    /**
     * Returns the domain name
     * @return the domain name
     */
    public String getName();
    
    /**
     * Returns whether the domain is verified
     * @return true if verified, false otherwise
     */
    public boolean isVerified();
}

Organization Events

Event interfaces for organization membership lifecycle management.

public interface OrganizationModel {
    
    /**
     * Base interface for organization membership events
     */
    interface OrganizationMembershipEvent extends ProviderEvent {
        OrganizationModel getOrganization();
        UserModel getUser();
        KeycloakSession getSession();
    }
    
    /**
     * Event fired when a user joins an organization
     */
    interface OrganizationMemberJoinEvent extends OrganizationMembershipEvent {
        static void fire(OrganizationModel organization, UserModel user, KeycloakSession session);
    }
    
    /**
     * Event fired when a user leaves an organization
     */
    interface OrganizationMemberLeaveEvent extends OrganizationMembershipEvent {
        static void fire(OrganizationModel organization, UserModel user, KeycloakSession session);
    }
}

Usage Examples

Creating and Managing Organizations

import org.keycloak.organization.OrganizationProvider;
import org.keycloak.models.OrganizationModel;
import org.keycloak.models.OrganizationDomainModel;
import org.keycloak.models.KeycloakSession;

public class OrganizationManagementExample {
    
    public void createOrganization(KeycloakSession session) {
        OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
        
        // Create a new organization
        OrganizationModel org = provider.create("Example Corp", "example-corp");
        org.setDescription("Example Corporation for demonstrating organization management");
        org.setEnabled(true);
        
        // Add domains to the organization
        Set<OrganizationDomainModel> domains = new HashSet<>();
        domains.add(new OrganizationDomainModel("example.com", true)); // verified domain
        domains.add(new OrganizationDomainModel("example.org", false)); // unverified domain
        org.setDomains(domains);
        
        // Set custom attributes
        Map<String, List<String>> attributes = new HashMap<>();
        attributes.put("industry", Arrays.asList("Technology"));
        attributes.put("size", Arrays.asList("Enterprise"));
        org.setAttributes(attributes);
    }
    
    public void findOrganizationByDomain(KeycloakSession session, String email) {
        OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
        
        // Extract domain from email
        String domain = email.substring(email.indexOf("@") + 1);
        
        // Find organization by domain
        OrganizationModel org = provider.getByDomainName(domain);
        if (org != null) {
            System.out.println("Found organization: " + org.getName());
        }
    }
}

Managing Organization Members

public class OrganizationMembershipExample {
    
    public void manageMembership(KeycloakSession session, RealmModel realm) {
        OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
        OrganizationModel org = provider.getByAlias("example-corp");
        
        // Add a managed member (lifecycle bound to organization)
        UserModel managedUser = session.users().getUserByEmail(realm, "employee@example.com");
        if (managedUser != null) {
            provider.addManagedMember(org, managedUser);
        }
        
        // Add an unmanaged member (existing user joining organization)
        UserModel unmanagedUser = session.users().getUserByEmail(realm, "partner@otherdomain.com");
        if (unmanagedUser != null) {
            provider.addMember(org, unmanagedUser);
        }
        
        // Search members with filters
        Map<String, String> filters = new HashMap<>();
        filters.put(UserModel.SEARCH, "john");
        filters.put(MembershipType.NAME, MembershipType.MANAGED.name());
        
        Stream<UserModel> managedMembers = provider.getMembersStream(org, filters, false, 0, 10);
        managedMembers.forEach(user -> {
            System.out.println("Managed member: " + user.getEmail());
        });
        
        // Get member count
        long memberCount = provider.getMembersCount(org);
        System.out.println("Total members: " + memberCount);
    }
    
    public void checkMembershipStatus(KeycloakSession session, UserModel user) {
        OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
        
        // Find all organizations the user belongs to
        Stream<OrganizationModel> userOrganizations = provider.getByMember(user);
        userOrganizations.forEach(org -> {
            boolean isManaged = provider.isManagedMember(org, user);
            System.out.println("User is " + (isManaged ? "managed" : "unmanaged") + 
                             " member of " + org.getName());
        });
    }
}

Identity Provider Association

public class OrganizationIdentityProviderExample {
    
    public void associateIdentityProvider(KeycloakSession session, RealmModel realm) {
        OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
        OrganizationModel org = provider.getByAlias("example-corp");
        
        // Get an identity provider
        IdentityProviderModel idp = realm.getIdentityProviderByAlias("corporate-saml");
        
        if (idp != null) {
            // Associate identity provider with organization
            boolean associated = provider.addIdentityProvider(org, idp);
            
            if (associated) {
                // Configure email-based routing
                Map<String, String> config = idp.getConfig();
                config.put(OrganizationModel.IdentityProviderRedirectMode.EMAIL_MATCH.getKey(), "true");
                idp.setConfig(config);
                
                realm.updateIdentityProvider(idp);
                System.out.println("Identity provider associated with organization");
            }
        }
        
        // List all identity providers for the organization
        Stream<IdentityProviderModel> orgIdps = provider.getIdentityProviders(org);
        orgIdps.forEach(identityProvider -> {
            System.out.println("Organization uses IDP: " + identityProvider.getAlias());
        });
    }
}

Organization Search and Filtering

public class OrganizationSearchExample {
    
    public void searchOrganizations(KeycloakSession session) {
        OrganizationProvider provider = session.getProvider(OrganizationProvider.class);
        
        // Search by name or domain
        Stream<OrganizationModel> searchResults = provider.getAllStream("example", false, 0, 10);
        searchResults.forEach(org -> {
            System.out.println("Found: " + org.getName() + " (" + org.getAlias() + ")");
        });
        
        // Search by attributes
        Map<String, String> attributes = new HashMap<>();
        attributes.put("industry", "Technology");
        Stream<OrganizationModel> attrResults = provider.getAllStream(attributes, 0, 10);
        
        // Get organization count
        long totalOrgs = provider.count();
        System.out.println("Total organizations: " + totalOrgs);
        
        // Check if organizations are enabled in the realm
        boolean orgEnabled = provider.isEnabled();
        System.out.println("Organizations enabled: " + orgEnabled);
    }
}

Organization management provides a comprehensive framework for multi-tenant scenarios, enabling domain-based user routing, federated identity integration, and hierarchical membership management within Keycloak realms.

Install with Tessl CLI

npx tessl i tessl/maven-org-keycloak--keycloak-server-spi@26.2.1

docs

authentication-sessions.md

component-framework.md

core-models.md

credential-management.md

index.md

organization-management.md

provider-framework.md

session-management.md

user-storage.md

validation-framework.md

vault-integration.md

tile.json