Skip to content

Move ThunderID Management feature capabilities (Groups, Roles, etc.) - #155

Merged
brionmario merged 1 commit into
thunder-id:mainfrom
brionmario:feat-group-role-details
Nov 6, 2026
Merged

brionmario merged 1 commit into
thunder-id:mainfrom
brionmario:feat-group-role-details

Conversation

@brionmario

@brionmario brionmario commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Purpose

The SDK ships details views for users, agents and applications, but none for groups or roles. An app that shows one, such as the ThunderID Admin Console, fetches the group or role itself, draws its name and description, and then places GroupMembers, or RolePermissions and RoleAssignments, under it. This adds GroupDetails and RoleDetails, so that view comes from the SDK.

  • GroupDetails fetches the group and shows its name, description and organization unit, with its members under them.
  • RoleDetails does the same for a role, with what it grants and who holds it.
  • Both are read only by default. editable lets the signed-in user add and remove members or assignments, which are offered from the group's or role's own organization unit. deletable adds a delete action that asks for confirmation, then reports the deletion so the app can navigate away.
  • administrationMode: flow deletes the group or role, and removes members and assignments, through the administration flow the server configures for it, which can revoke grants and end sessions first. With no flow configured, the API is called directly.
  • A read-only role is never offered for deletion, as with read-only agents.

Folder layout. The UI group for these components was components/admin, while the data layer, the hooks and composables, and the specification all say management. This renames components/admin to components/management in React, Vue and Next.js (and Next.js's internal client/admin.ts to client/management.ts), so every SDK uses the same names: api/{account,auth,management} and components/{account,auth,management,common}. Only folder paths change: exports, component names and the admin.* translation keys stay as they are.

Approach

  • Styled and Base variants for React and Vue, following AgentDetails. BaseGroupDetails and BaseRoleDetails hold no data: the group or role, loading and error state, and onDelete are props. The embedded sections are slots (members for groups; permissions and assignments for roles), as a React prop or a Vue named slot.
  • Custom rendering: a children function (React) or the default scoped slot (Vue) receives group/role, isLoading, error, isDeleting and onDelete. onDelete is undefined unless deletion is allowed and the record is deletable. It replaces the whole view, embedded sections included.
  • One fetch for a role: the role already carries its permissions, so RoleDetails renders BaseRolePermissions from it rather than mounting RolePermissions, which would fetch the role again.
  • Cache invalidation after a delete: groups, memberships and role assignments for a group; roles and role assignments for a role.
  • Next.js: GroupDetails and RoleDetails wrappers, plus the Base* exports in client/admin. Nuxt: all four are added to the management auto-imports.
  • Strings: admin.groups.details.* and admin.roles.details.* (overview, error, delete action, confirmation and error) in all 9 locales.
  • Playgrounds: stories for both components, with sample and live data and controls for editable, deletable and administrationMode, in the React, Vue, Next.js and Nuxt playgrounds. React also has a custom-rendering story.

New management operations

The SDK development specification (0.11, thunder-id/thunderid#6080) adds these resources; this PR implements them, under the same management rules as the rest: the signed-in user's token, the URL from an explicit url, then the endpoints override, then baseUrl plus the collection, a replaceable fetcher, and no side effects.

  • Credential configurations (OpenID4VCI): getCredentialConfigurations, getCredentialConfiguration, createCredentialConfiguration, updateCredentialConfiguration, deleteCredentialConfiguration. Collection openid4vci/credential-configurations, endpoint key credentialConfigurations.
  • Presentation definitions (OpenID4VP): getPresentationDefinitions, getPresentationDefinition, createPresentationDefinition, updatePresentationDefinition, deletePresentationDefinition. Collection openid4vp/presentation-definitions, endpoint key presentationDefinitions.
  • Client registrations (RFC 7591/7592): registerClient, getClientRegistration, updateClientRegistration, deleteClientRegistration. Collection oauth2/dcr/register, endpoint key clientRegistrations.
    • Models are in the platform's casing and map to the snake_case wire format both ways.
    • Update replaces the metadata in full, sets client_id from the argument, and may send the client's current secret for the server to check (the server never stores it).
    • The secret is returned only on registration. The SDK never logs it, and it never appears in a URL or an error.
  • Gateway master: getGatewayMaster, getGatewayMasterHistory, getGatewayMasterResource, on the existing gateways resource. Each path segment is percent-encoded.
  • OAuth errors: an {error, error_description} body is read into serverError (code and message), so client registration errors carry the server's reason. 401, 403 and 404 keep distinct codes. Management error bodies, which carry code, are unaffected.
  • The two new lists take no paging parameters, because the server endpoints define none and return a plain array (like gateways).
  • Node: ThunderIDNodeManagementClient gains credentialConfigurations, presentationDefinitions and clientRegistrations (register, get, update, delete), and gateways.getMaster, getMasterHistory and getMasterResource. The three collections join the management relay allowlist that the Next.js and Nuxt relays use.
  • React and Vue re-export the new functions and types, and useManagementEndpoint accepts the new keys.

Verified locally: build passes for javascript, browser, node, react, vue, nextjs and nuxt, and typecheck for every package except nuxt (vue-tsc missing locally). Tests: javascript 1155, node 205, nextjs 148, React management components 87. The Vue run has failures in the auth flow tests (flow-select-field, sign-up and device code); they fail the same way without this PR.

Organization units and the rest of the 0.10 surface

Implements the rest of the SDK development specification 0.11 (thunder-id/thunderid#6080), including the organization operations it now defines for the organization unit work in flight (thunder-id/thunderid#5625, #6302; server side in #6303 on feature/ou-authz-and-projects).

Organization units

  • getAccessibleOrganizationUnits reads /users/me/ous (optional scope: siblings, paging); getCurrentOrganizationUnit reads the ouId, ouHandle and ouName claims, for display only.
  • Sign-in bounded to a unit with organizationUnitId: redirect mode authorizes at /ou/{ouId}/oauth2/authorize and redeems the code at /ou/{ouId}/oauth2/token; embedded mode sends ouId only on the flow start; backend mode passes ouId to the backend sign-in. The unit id is percent-encoded.
  • switchOrganizationUnit: signs in again bounded to the unit, reusing the SSO session; success replaces the whole token set (the refresh token is bound to its unit), failure leaves the old session exactly as it was. unauthorized_client maps to one documented error.
  • The sign-in flow renders the server's Resolve OU step (a typed unit before sign-in, a choice of eligible units after).
  • OrganizationUnitSwitcher and BaseOrganizationUnitSwitcher (account group), with custom render, paging and translated errors in every shipped locale.

Management

  • Sharing policies and overlay rules for roles and flows (overlay ownership read from isOwned, isOwnedByOU or owned, which also fixes user and application overlays).
  • Flow variables (ouId required, as the server requires it), groups by handle path, projects (endpoint key projects), authorization detail types (endpoint key authorizationDetailTypes) and the public supported authorization details types.
  • RolePermissions edits a role's permissions when editable (off by default, never for read-only roles, removal confirmed); RoleDetails passes its editable through.

Components for projects, organization units and sharing (UI requirements 11 and 12 in thunder-id/thunderid#6080), in React and Vue, with Next.js wrappers and Nuxt auto-imports

  • ProjectList, ProjectCreate, ProjectDetails and ProjectSwitcher. Projects are a control plane concept, and a project id is not an organization unit id. The switcher keeps the current project as client-side context (currentProject/setCurrentProject on the provider; persisted per vendor in localStorage, read after mount so server rendering stays safe).
  • getApplications/getAgents take an optional projectId query parameter and the application and agent create requests an optional projectId (an agent's ouId becomes optional). ApplicationList and AgentList default projectId to the current project, and ApplicationCreate and AgentCreate send it when the app passes no organization unit. Other creates keep their organization unit default. AgentList hides its search while a project scopes it, because the server can't combine another filter with projectId.
  • OrganizationUnitList (root units or the children of parentId), OrganizationUnitCreate and OrganizationUnitDetails (child units and the users, groups and roles in the unit, read only).
  • SharingPolicies for a user, application, role or flow: paged, with create, edit and delete only when editable (delete confirmed, read-only policies offer no actions), and the overlay rules for an ouId.
  • Server refusals map to translated messages by code: PRJ-1006/PRJ-1012 (id or handle in use), PRJ-1007 (handle can't change), OU-1004/OU-1008 (name or handle in use), OU-1006 (unit still has children), OU-1012 (declarative). toManagementErrorMessage takes an optional code-to-key map for this.
  • Each has a Base variant and a custom render, strings in all 9 locales, tests, and playground stories (React, Vue, Next.js, Nuxt) including Custom rendering. The Nuxt auto-import count test now expects 26.

Optional operations

  • Pushed authorization requests: config key pushedAuthorizationRequests (default false; never overrides a server that requires PAR).
  • CIBA already matched the canonical names. The user-side device grant is now verifyDeviceCode (the old name stays as a deprecated alias).
  • Node only, never exported from browser, React or Vue (a test checks it): startDeviceAuthorization/pollDeviceAuthorization, introspectToken, and access evaluation (evaluateAccess, evaluateAccesses, searchActions; endpoints from the AuthZEN metadata, the secret in Direct-Auth-Secret, a denial returned as a result). Express gains a requireAccess guard.

Framework notes: the browser tries a silent prompt=none switch in an iframe before a full redirect. Next.js and Nuxt switch through server actions and routes (always a redirect); Nuxt adds GET /api/auth/user/organization-units. useThunderID exposes switchOrganizationUnit and the current unit.

Also fixed: the Nuxt test that counts management auto-imports expected 16 and now expects 18, after GroupDetails and RoleDetails.

Verified locally: build passes for javascript, browser, node, express, react, vue, nextjs and nuxt, and typecheck for all but nuxt (vue-tsc is missing locally). Tests: javascript 1244, browser 154, node 233, express 30, nextjs 160, nuxt 255, react 685 (all pass). Vue: 465 pass; 13 fail in six auth and primitive test files (flow-select-field, user-select-flow-wiring, authorization-details, consent-decisions, key-value-list, otp-field), which fail the same way without this PR. Prettier is clean on every changed file.

On top of attribute verification (#145). The PR is rebased onto main, which added self user attribute verification and released @thunderid/react 1.14.0 without the components here. The Vue BaseVerifyAttribute reads the shared admin translation helper from components/management/shared, the playgrounds keep the verification stories next to the new ones, and the Nuxt module serves both the self-flow and organization-units routes.

Related Issues

Related PRs

Checklist

  • Followed the contribution guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
    • TSDoc on every component and prop, and playground stories.
  • Tests provided. (Add links if there are any)
    • Unit Tests (React adminComponents.test.tsx and Vue admin-components.test.ts: the built-in view, members and assignments listed from the record's organization unit, one role fetch, delete after confirmation, no delete for a read-only role, custom rendering, and load errors.)
    • Integration Tests
  • Breaking changes. (Fill if applicable)
    • Breaking changes section filled.
    • breaking change label added.
  • Cross-SDK parity. Exactly one of parity/prs-raised or parity/prs-not-needed added.
    • If parity/prs-raised, the port links are posted as a reply on the parity check's comment.

Verified locally, after the rename: the React management tests (87) and Vue management tests (68) pass, React, Vue, Next.js and Nuxt build, typecheck passes for React, Vue and Next.js, and ESLint reports nothing new. The Nuxt typecheck was not run (vue-tsc is missing from the local install).

Security checks

  • Followed secure coding standards.
  • Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets.

@brionmario brionmario added the parity/prs-raised Ports exist in the other SDKs, or are recorded as not applying there label Nov 4, 2026
@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

🔀 Cross-SDK feature parity, ports raised

This pull request is labelled parity/prs-raised, so the capability it introduces is expected in the other ThunderID SDKs as well.

Ports (DO NOT EDIT)

  • thunder-id/ios-sdks, iOS => #42
  • thunder-id/android-sdks, Android => #50
  • thunder-id/flutter-sdks, Flutter => #64

3 of 3 sibling SDKs accounted for.

Every sibling SDK is accounted for.

The contract is in the SDK development specification.

@brionmario
brionmario force-pushed the feat-group-role-details branch from ded9536 to ef5df2c Compare November 4, 2026 15:21
@brionmario brionmario changed the title Add GroupDetails and RoleDetails admin components Add GroupDetails and RoleDetails, and rename the admin components group to management Nov 4, 2026
@brionmario
brionmario force-pushed the feat-group-role-details branch from ef5df2c to ee5fa36 Compare November 4, 2026 15:31
@brionmario brionmario changed the title Add GroupDetails and RoleDetails, and rename the admin components group to management Add group and role details, verifiable credential, client registration and gateway master operations, and rename the admin components group to management Nov 4, 2026
@brionmario
brionmario force-pushed the feat-group-role-details branch from ee5fa36 to ed7a872 Compare November 4, 2026 16:42
@brionmario brionmario changed the title Add group and role details, verifiable credential, client registration and gateway master operations, and rename the admin components group to management Add organization unit sign-in and switching, the remaining management operations, group and role details, and rename the admin components group to management Nov 4, 2026
@brionmario
brionmario force-pushed the feat-group-role-details branch from ed7a872 to 6971ff7 Compare November 4, 2026 17:48
@brionmario brionmario changed the title Add organization unit sign-in and switching, the remaining management operations, group and role details, and rename the admin components group to management Add organization unit sign-in and switching, the remaining management operations and components, group and role details, and rename the admin components group to management Nov 4, 2026
… operations and components, group and role details, and rename the admin components group to management

Show a group with its members, and a role with its permissions and assignments, in one view. Both fetch the record, show its name, description and organization unit, embed the existing GroupMembers, RolePermissions and RoleAssignments, and can delete it (through its administration flow in flow mode) after confirmation. Read-only roles are never offered for deletion. Ships for React and Vue with Base variants and custom rendering, Next.js wrappers, Nuxt auto-imports, strings in every locale, tests and playground stories.

Rename the components/admin folder to components/management in React, Vue and Next.js, so the UI group matches the data layer (api/management, hooks/management, composables/management) and the specification's management operations. Folder paths only: exports, component names and the admin.* translation keys are unchanged.

Add management operations for credential configurations (OpenID4VCI,
openid4vci/credential-configurations) and presentation definitions
(OpenID4VP, openid4vp/presentation-definitions), dynamic client
registration (RFC 7591/7592, oauth2/dcr/register: register, get, update,
delete), and a gateway's master, its history and one resource's history.
Each resolves its URL like the other management resources, with the
credentialConfigurations, presentationDefinitions and clientRegistrations
endpoint keys. Client registrations map the snake_case wire format, set
client_id from the argument on update and may send the current secret for
the server to check, and keep the secret out of logs and printed output.
An OAuth error body ({error, error_description}) is read into serverError,
and 401/403/404 keep distinct codes. Path parameters are percent-encoded
per segment.

Add the rest of the SDK specification's 0.10 surface. Organization
operations: list the units the signed-in user can access
(/users/me/ous), read the current unit from the token's claims, sign in
bounded to a unit (/ou/{ouId}/oauth2/authorize and token in redirect
mode, ouId on the flow start in embedded mode, ouId on the backend
sign-in), switch units (a failed switch leaves the session as it was),
render Resolve OU flow steps, and an OrganizationUnitSwitcher
component. Management: sharing policies and overlay rules for roles and
flows, flow variables, groups by path, projects, authorization detail
types and the public authorization details types, and editable
RolePermissions. Optional operations: pushed authorization requests
(pushedAuthorizationRequests), device authorization, and CIBA where the
platform's spec scope allows it.

JavaScript also adds, in Node only, the device side of device
authorization, token introspection and access evaluation (AuthZEN, with
an Express requireAccess guard), renames the user-side device grant to
verifyDeviceCode (the old name stays as a deprecated alias), and renders
the Resolve OU input the flow renderers used to skip.

Add components for them: ProjectList, ProjectCreate, ProjectDetails and a
ProjectSwitcher that keeps the current project as client-side context,
OrganizationUnitList, OrganizationUnitCreate and OrganizationUnitDetails,
and SharingPolicies for a user, application, role or flow, in React and
Vue with Next.js wrappers and Nuxt auto-imports. A project id is not an
organization unit id: application and agent lists and creates take the
current project as projectId (the operations gain it), other creates keep
their organization unit default, and AgentList offers no search while a
project scopes it, since the server can't combine the two. Server
refusals map to translated messages by code.

Signed-off-by: Brion <info@brionmario.com>
@brionmario
brionmario force-pushed the feat-group-role-details branch from 6971ff7 to 1c568a1 Compare November 6, 2026 05:11
@brionmario brionmario changed the title Add organization unit sign-in and switching, the remaining management operations and components, group and role details, and rename the admin components group to management Move ThunderID Management feature capabilities (Groups, Roles, etc.) Nov 6, 2026
@brionmario
brionmario merged commit 7db0d71 into thunder-id:main Nov 6, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parity/prs-raised Ports exist in the other SDKs, or are recorded as not applying there

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants