Relationship authorization

Use a trusted backend credential to call Relationship on behalf of your application. API caller identity, project access and the business principals stored in a relationship are separate boundaries.

Credential and transport

Credential Contract
M7 access token Signed compact JWT; treat its value as opaque. Send Authorization: Bearer ACCESS_TOKEN.
API audience Exact audience https://api.relationship.service.m7.org; a frontend token is not automatically an API credential.
Caller A user or confidential machine admitted by the receiving service; current roster status must be active.
Sender binding Use an unbound Bearer token. Sender-constrained tokens are rejected with sender_proof_required; this API does not implement a DPoP protected-resource flow.

The service validates token signature, the permitted RS512 algorithm, accepted issuer (https://sso.user.m7.org or id.m7.org), trusted signing certificate source, audience and time constraints. It then uses receiver-authenticated M7 admission checks. Decoding a JWT or possessing a signed token does not establish project authority. Never authorize your users from decoded token claims alone.

ID tokens, refresh tokens, client secrets, authorization codes and API keys are not substitutes for this access token. Send the access token only in the Authorization header, over HTTPS; keep it out of URLs, request bodies, logs and analytics. Keep confidential client credentials and refresh packages in server-side secure storage.

Obtain, replace and revoke tokens

Use M7 SSO with the OAuth client and audience registered for your integration. Its discovery document is at https://sso.user.m7.org/.well-known/openid-configuration.

Caller Token acquisition
Application acting for a user Authorization code with PKCE; device authorization for an input-constrained client.
Confidential backend acting as itself client_credentials, with the client's registered authentication method.

For a confidential client configured for client_secret_basic:

curl --fail-with-body --silent --show-error \
  --request POST 'https://sso.user.m7.org/token' \
  --user 'CLIENT_ID:CLIENT_SECRET' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'aud=https://api.relationship.service.m7.org'

Request scope=orgs as well when using an organization workspace. The OAuth client policy must permit that audience, grant and scope. Select an issuance policy that returns an unbound Bearer token for this API.

Observe SSO's returned expires_in; do not assume a fixed lifetime. A machine token has no refresh token: authenticate the client again to obtain a replacement. User-authorized refresh credentials and their binding package go to SSO's token endpoint under the applicable SSO lifecycle. Relationship does not refresh tokens. Revoke credentials through SSO or the owning application's credential controls; revoked, expired or denied admission is not overridden by project membership. After a 401, obtain a valid replacement; repeated 403 responses require an access decision rather than token retries.

Project authority and application principals

The effective workspace principal must have an active membership in the project's pinned Management group. Receiving-service Root or Admin status does not supply another project's membership. Use the returned project context to inspect current capabilities.

Operation Required project capability Additional role boundary
Read project context project.view Active project membership.
Read spaces/subspaces space.list Current optional read grant.
Read current relationships, requests or activity relationship.list Current optional read grant.
Create/save/remove relationships; create/decide requests relationship.manage Project Owner or Admin.
Read or acknowledge mailbox events mailbox.notifications Current mailbox grant; acknowledgement rechecks admission.

Read grants can be changed independently of membership. Current role, capabilities and admission are checked again during mutations. A business reference such as {"namespace":"example.app","principal_id":"PERSON_UUID"} does not enroll that person as an API caller or project operator. The consuming application must verify that reference and decide which user can create, accept, cancel or remove a relationship before forwarding a command.

Personal and organization workspaces

Omit organization selection for the caller's personal workspace. Select an organization with header Org: ORGANIZATION_UUID or body field org_id. The value must be a non-nil dashed UUID. If both are supplied they must match case-insensitively; null or malformed selections are rejected. Do not send organization names, membership objects or capability lists as authority.

Organization operations require an access token with orgs scope and a current organization disclosure to Relationship. Every selected-organization request, including reads, obtains current organization facts. For a machine, the validated OAuth client must be the actual machine caller. The organization's stable principal and own project membership supply workspace access; the machine's personal memberships are not inherited. The actual actor remains separately attributed in relationship events.

Current direct Management tag names resolve through the Relationship catalogue. Explicit selections replace role fallback; a nonempty selection of unknown names grants nothing. Only a verified empty selection can use its configured role fallback. Resolved organization grants are intersected with project capabilities. A tag never promotes the project membership role.

For an unbound Bearer token, no Org-DPoP companion header is required. That header concerns an organization disclosure proof; it does not add DPoP protected-resource support or make a sender-constrained token acceptable here.

curl --fail-with-body --silent --show-error \
  --request POST 'https://api.relationship.service.m7.org/v1/projects/context' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --header 'Org: ORGANIZATION_UUID' \
  --header 'Content-Type: application/json' \
  --data '{"project_id":"PROJECT_UUID"}'

Authorization failures

Failure Action
HTTP 401; missing_token, invalid_token or token_required Supply an unexpired M7 token for the exact API audience.
HTTP 401; sender_proof_required Use an authorized unbound Bearer issuance profile.
Admission or operation code 403 Check active receiving admission, workspace disclosure, project membership and the required capability.
Admission HTTP 503 or operation body code 5xx Authorization verification is unavailable; fail closed and retry with backoff.
Code 400 for organization selection Correct its UUID and conflicting selections.

Inspect the HTTP status, status and data.code, as described in the service response rules. Credentials must never be resent to an arbitrary endpoint named in an error message.