Feature Focus: Access Control in WeftID

Real organizations are not trees. People belong to a function and a region and a project at once, and a strict hierarchy forces you to choose which of those is the real one, then work around the choice with duplicate groups.

WeftID models that overlap directly. A department, a project, a region, a class of contractor: each can be a group in its own right, and a person sits at the intersection of the ones that apply to them, duplicated nowhere. Access is granted on those groups, so it follows the shape of the organization you actually have rather than a flattened picture of it.

One grant model, three protocols

WeftID protects three kinds of application: SAML service providers, OIDC relying parties signing users in with a "Sign in with WeftID" button, and HTTP applications behind forward auth that have no identity support of their own. All three resolve access through the same code path.

Every application is in one of two states. Either it is available to all, and every active user in the tenant can reach it, or it is group-based, and a user needs a grant. There is no third mode, and there is no per-user grant: you cannot hand one person access to one application as a one-off. The answer to "why does this person have access to that app" is always the name of a group, and the access review is a review of group membership.

Denials are enforced early and recorded. An OIDC user without a grant is turned away at the authorize step, before any code or token is issued, and never sees a consent screen. The denial lands in the audit log like any other security event.

Groups are a graph, not a tree

WeftID groups form a directed acyclic graph, so a group can have several parents and each dimension can be its own group with membership sitting at the intersection. In the graph below, Clinical Research Coordinators sits beneath both Clinical Operations and Research & Innovation. The coordinators who run trials belong to both departments at once, without being copied into each. The only rule the model enforces is that a group cannot be its own ancestor.

WeftID group graph. All Staff sits at the top, with the departments connecting up into it. Clinical Research Coordinators connects up into both Clinical Operations and Research & Innovation at once. Every connecting line is an arrow pointing up toward the parent, labelled with the number of members that flow along it.
The interactive graph view, on the group list and each group's detail page. Clinical Research Coordinators has two parents, which a tree cannot express. Each line points up toward the parent and carries the count of members flowing along it: the coordinators are counted into both Clinical Operations and Research & Innovation, and each department in turn into All Staff.

Membership is explicit. Access flows upward.

Membership does not flow down. Adding someone to Clinical Operations does not make them a member of the groups beneath it. If you want them in Clinical Research Coordinators, you add them there.

Access flows up. A user's effective groups are the ones they belong to directly, plus every ancestor of those groups. A member of Clinical Research Coordinators is therefore an effective member of Clinical Operations and Research & Innovation above them, so an application granted to either department is reachable. That is exactly what a coordinator working across both sides needs, and it is the same upward path the member counts trace in the graph above.

Grants therefore apply to the group named and everything under it. A new team created under Clinical Operations starts with the access Clinical Operations has, and a team moved out of it loses that access when the relationship is removed.

Groups the upstream directory already owns

Not every group should be maintained in WeftID. Groups have a type: WeftID groups are managed by your admins, and IdP groups are synced from an upstream identity provider. IdP groups are created automatically when an identity provider sends group assertions, their membership is read-only in WeftID, and it refreshes on each SAML sign-in.

Access decisions can then ride on the directory that is already the source of truth. If Okta or Entra already knows who is in Finance, you assign the application to the synced Finance group and stop maintaining a second copy of that list. Both kinds of group are grant targets, and both participate in the hierarchy, so a synced group can sit under a WeftID group you use for structure.

The same memberships propagate outward. Outbound SCIM pushes groups to downstream applications, and by default it pushes effective membership, so the downstream app sees the flattened list that matches the access decision WeftID just made rather than a partial one it has to interpret.

The application learns only what it needs

An application that receives a user's full group list learns your org chart, so WeftID's default is narrower than that. When group claims are enabled on a service provider, the group assertion scope decides what is actually sent, and the default scope is access-granting groups only: the application is told which groups gave this user access to it, and nothing about the rest of the user's memberships. The scope can be widened to top-level groups or all groups, per application or tenant-wide, when an application genuinely needs the fuller picture for its own internal roles.

The SAML consent screen shows the user exactly which groups will be shared before the sign-in completes.

OIDC applies the same principle through scopes. A relying party gets the groups claim only if it requests the groups scope, and identity claims only if it requests profile or email. The subject identifier it always receives is a stable WeftID user ID, never the email address.

Taking access away

Removing a user's group access, or narrowing an application from available-to-all, immediately revokes that user's outstanding OAuth2 and OIDC tokens, and the refresh grant re-checks access, so a revoked user cannot mint a fresh access token on the strength of a refresh token they were issued before the change. Deactivating a user terminates their session and revokes their tokens at once. Applications behind forward auth are re-checked on every request, so a removed grant takes effect on the user's next page load.

Who can perform any of this is bounded by role. Admins manage groups and membership, which is the day-to-day work of access management, but cannot change security settings or touch identity provider configuration. Only super admins do that. B2B service accounts automating group membership through the API carry an explicit service role that bounds them the same way, and their tokens can be revoked by deactivating the client.

In short

WeftID answers "who can reach what" with a single mechanism: a grant to a group, resolved identically for SAML, OIDC, and forward-auth applications, inherited down the hierarchy from the group you granted, and revoked the moment you remove it. There is no per-user exception path, so the group list shows the whole picture.

Read the group-based access guide for the full reference, view the source on GitHub, or try it out.