Endpoints#
Every endpoint the package publishes, by layer.
Important
Every authenticated REST service is registered with zope2.View, and
authorization happens inside the service class. Reading the registration
alone understates what a caller needs. The "Requires" column below is what the
code actually enforces. The anonymous services are registered zope.Public
instead: zope2.View is inherited from the site root, so a site that takes
View away from Anonymous would refuse them.
Core layer#
Present in every installation.
Method |
Path |
Requires |
Purpose |
|---|---|---|---|
GET |
|
anonymous |
Providers to offer on the login page. Enabled and shown only. Also available as a |
POST |
|
anonymous |
The provider redirects here; completes a sign-in. |
POST |
|
anonymous |
Send a single-use sign-in link. Answers identically whether or not the address is known. |
POST |
|
anonymous |
Redeem a link. Burns the token. |
GET |
|
authenticated |
The caller's own profile. Also available as a |
POST |
|
authenticated |
Answer |
GET |
|
authenticated |
The caller's own sign-in methods. |
POST |
|
authenticated |
Link a new sign-in method. |
DELETE |
|
authenticated |
Unlink one. Refused for the last remaining method. |
GET |
|
authenticated |
The profile content types. |
PATCH |
|
see source |
Update profile fields. |
GET |
|
anonymous |
A user's picture: the Profile's when it has one, the member portrait otherwise. The |
GET |
|
|
Members of a group. |
GET |
|
|
One user's sign-in methods, for administrators. |
GET |
|
|
Drivers available to configure, each with its settings schema and default icon. |
GET |
|
|
Configured providers, or one with |
POST |
|
|
Add a provider. |
POST |
|
|
Fetch the provider's discovery document, cache cleared first, and report what came back. |
GET |
|
|
One provider as a registry fragment a profile can ship. Carries the client secret in the clear. |
GET |
|
|
Every provider as one registry document, in their order. Carries every client secret in the clear. |
PATCH |
|
|
Reorder every provider, with |
PATCH |
|
|
Change one. |
DELETE |
|
|
Remove one. Linked identities are kept. |
GET |
|
|
Authentication events. |
@group-members is the one with a compound rule: Manage users, or
membership of the group being asked about.
Three answers worth knowing#
Endpoint |
Answers |
|---|---|
|
Where the caller's |
|
The people in one group, named rather than only listed as userids, plus the nesting around it and a search within it. |
|
Which providers a person has configured—named, dated, and flagged when the provider has since been disabled or removed—and when they last authenticated. One user at a time: the audit log is bounded per user, so folding this into the |
@user-account allows a caller asking about themselves without Manage users.
@confirm-email refusals#
Checked in this order.
Status |
|
When |
|---|---|---|
401 |
|
The caller is anonymous. |
404 |
|
The caller has no profile. |
400 |
|
The body names no |
409 |
|
The profile is not waiting on a confirmation. Reordering addresses is a |
400 |
|
The address is not one of the profile's verified addresses. |
my-profile as a component#
The profile gate asks its question on every navigation, and a navigation to a
content route is already a request.
my-profile is registered as an expandable component so the answer rides along
with the page, and volto-identity adds it to Volto's apiExpanders.
Fact |
Value |
|---|---|
Registered on |
Any content, not the site root alone |
|
The site's |
Expanded |
The same body the endpoint returns |
Anonymous |
The component is absent entirely, not an |
The anonymous rule is the one that differs from every other component here,
which publish a URL when unexpanded.
Volto's apiExpanders has no way to mark an entry authenticated-only, so
?expand=my-profile arrives on anonymous content requests as well; answering
with nothing keeps a public site's payload exactly as it was.
A membership listing#
What GET @group-members/<group id> answers with. ?query= narrows the rows
to the members whose full name or login contains it, ignoring case.
Key |
What it holds |
|---|---|
|
This listing. |
|
The group id. |
|
One page of rows, sorted by name. See the next section. |
|
How many members match |
|
Everybody in the group, nested memberships included. The same whatever |
|
The members in the group itself rather than through a nested group. The same whatever |
|
The groups nested inside this one, at any depth. |
|
The groups this one is directly nested inside. |
|
The |
A membership row#
Each entry in the items of @group-members:
Key |
What it holds |
|---|---|
|
The person's |
|
Their userid. |
|
The full name, falling back to the login and then the userid, so a row is never blank. |
|
The login name. |
|
The same URL as |
|
The groups this person is directly in, so a page listing an outer group can say where each of them came from. |
No address. A membership listing is personal data about other people, and it is not a directory of contact details.
Every value is a catalog metadata column. That is what lets a group of a
thousand people be one query rather than a thousand object loads, so a
deployment adding a field to a row adds a metadata column to
identity-catalog.xml first, then subclasses GroupMemberSerializer, calls up
to it, and registers the subclass for its own browser layer. See
About profiles and groups for why the adapter is on the site rather
than on the brain.
Server layer#
Published only where the pas.plugins.identity.server:default profile has been
applied. These are bound to IIdentityServerLayer, so a site without that
profile does not publish them at all.
Method |
Path |
Requires |
Purpose |
|---|---|---|---|
GET |
|
|
Registered OAuth clients, or one with |
POST |
|
|
Register one. The secret is in this response and nowhere else. |
POST |
|
|
Mint a fresh secret. Same warning applies. |
PATCH |
|
|
Change title, redirect URIs, grants, scope, service user, allowed groups, and enabled. |
DELETE |
|
|
Remove one. |
GET |
|
|
Describe the signing ring. |
GET |
|
|
The server settings and their schema: issuer, consent screen, token lifetimes, and unreleased groups. Neither the client list nor the signing keys. |
PATCH |
|
|
Change those settings. An issuer that relying parties would not match is refused; a field outside the five is ignored. |
POST |
|
|
Rotate the signing key. Older keys stay in the ring so tokens already issued keep verifying. |
GET |
|
authenticated |
What a client is asking for, for the consent screen. |
GET |
|
authenticated |
Applications the caller has granted access to. |
DELETE |
|
authenticated |
Withdraw one. |
Browser views#
Path |
Layer |
Purpose |
|---|---|---|
|
core |
The control panel view. |
|
core |
Receives a logout token from a provider. See Enable back-channel logout. |
|
server |
The authorization endpoint. Public: the browser reaching it may be anonymous, and the view refuses an unauthenticated end user itself with the error code the specification names. |
|
server |
The token endpoint. Public: the caller is a server holding client credentials, authenticated inside against the client registry. |
|
server |
The signing keys, as JWKS. |
|
server |
The userinfo endpoint. |
|
server |
The discovery document. |
Back-channel logout#
POST @@backchannel-logout
One endpoint serves every configured provider. The logout token names its issuer, and that is how the package chooses the provider, and therefore the key to verify the signature with.
The endpoint follows OpenID Connect Back-Channel Logout 1.0. A token must satisfy all of the following:
Check |
Refused when |
|---|---|
Signature |
Not valid against the issuer's published key. |
Issuer and audience |
Either does not match. |
|
Outside the acceptable window. |
|
Already acted on. A repeat is a replay. |
Event |
No back-channel logout event declared. |
Subject |
Neither a |
|
Present. A nonce means somebody is passing an |
Note
Only sub-based logout is supported. This package does not track provider
session identifiers, so a token carrying only a sid is refused.
A logout for an identity this site has never seen answers 200, not an error.
There is nothing to end, and answering differently would tell an unauthenticated
caller which of a provider's subjects have accounts here.
To enable it, see Enable back-channel logout.
Why .well-known is registered oddly#
The path segment contains a dot, which a Zope view name cannot carry through
traversal in the usual way. So .well-known is registered as the view, and
the document name is traversed into it. A bare /.well-known/ is refused.
The published path is what a client expects:
https://id.example.com/.well-known/openid-configuration
The consent screen is the only page template#
server/browser/templates/consent.pt is the only page template in the package.
It is server-rendered, so a site running the server layer can be an identity
provider regardless of which frontend it runs itself.
Everything else a person sees is in the Volto add-on—see Frontend.