Authorization for api.post.m7.org

api.post.m7.org has two authorization models. Member routes use an M7 access token and scope stored resources to the resolved local principal. Proof routes do not use a Bearer token; they use an active proof job identifier and, when verifying or consuming a challenge, the one-time secret delivered for that job.

The API base URL is:

https://api.post.m7.org

Supported credentials

Credential Format and transport Where it applies Authorization boundary
M7 access token Signed compact JWT in Authorization: Bearer ACCESS_TOKEN /v1/members/* A valid token must resolve to an active local principal with the user, admin, or root role. Every member resource is scoped to that principal's local ID.
Proof job ID UUID in the JSON field job or job_id /v1/proof/get, /v1/proof/send, /v1/proof/verify, and /v1/proof/consume The job must exist, be active, and use the single or any proof policy. The ID alone can inspect the masked proof state or request a resend, so treat it as sensitive.
Proof code Six decimal digits in the JSON field secret or code; select kind: "code" /v1/proof/verify and /v1/proof/consume Must match the current active code for the supplied job. The default lifetime is 30 minutes; use the returned challenge.expires_at as authoritative.
Proof-token secret 64 hexadecimal characters in the JSON field secret or token; select kind: "token" /v1/proof/verify and /v1/proof/consume Must match the current active token-kind challenge for the supplied job. The default lifetime is 60 minutes; use the returned challenge.expires_at as authoritative.

ID tokens, refresh tokens, OAuth client secrets, proof codes, and proof-token secrets do not replace an M7 access token on member routes. Conversely, a Bearer token does not replace the job ID and one-time secret required by the proof flow.

Obtain an M7 access token

This service does not issue or refresh M7 access tokens. Obtain one through the M7 SSO API using the flow that matches the caller:

Caller M7 SSO flow
Browser, native application, or server-rendered application acting for a user Authorization code with PKCE
CLI, TV, or other input-constrained application Device authorization
Confidential service acting as itself client_credentials

Use the OAuth client and audience configured for this API. User-authorized flows may return a refresh package; send that package only to the M7 SSO token endpoint. A client_credentials token has no refresh token and must be reissued when it expires.

Never collect an M7 password in an integrating application. Never send a client secret, authorization code, refresh token, or refresh-package binding value to api.post.m7.org.

Send a Bearer request

The public member-route contract is the Bearer authorization scheme:

curl -sS https://api.post.m7.org/v1/members/job/list \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{}'

Use the scheme name Bearer, followed by one space and the access token. Do not put an access token in a URL, query string, JSON body, or cookie, and do not depend on compatibility token headers.

M7 access tokens are JWTs, but clients must treat them as opaque secrets. Decoded claims are not proof that the token is accepted or that the caller is authorized for a resource.

The service currently validates:

  • the compact JWT structure and signature;
  • the RS512 signature profile;
  • the id.m7.org token issuer;
  • an HTTPS signing-certificate source hosted by id.m7.org; and
  • the token's nbf, iat, and exp time claims when present.

The current service configuration does not require an audience match. Clients must still request and use a token intended for this API; the absence of a local audience check is not permission to reuse credentials across services.

Principal and ownership rules

After token validation, the service resolves the token identity to a local principal. A newly observed supported identity can be registered as an active principal; subsequent authorization uses the current local principal record.

Member routes allow these local roles:

Local role Member-route behavior
user May create and operate only on resources owned by that principal.
admin May call the same member routes, still scoped to that principal.
root May call the same member routes, still scoped to that principal.

The API derives owner from the resolved local principal ID and overwrites caller input. Supplying another principal's UUID, knowing another resource UUID, or holding an elevated role does not make a member route operate on another principal's resources.

A valid token can still be denied when the local principal is missing, inactive, or not assigned an allowed role. Always use the resource IDs returned for the same authenticated principal.

DPoP status

DPoP is not part of the supported api.post.m7.org authorization contract. The service validates the Bearer access token but does not validate a DPoP proof's signature, HTTP method and URL binding, access-token binding, freshness, unique identifier, or replay state. CORS allowance or header parsing for DPoP does not change that contract.

Send the Bearer request described above. Do not rely on a DPoP proof to authorize a member request.

Use the proof credentials

An authenticated principal creates and activates a proof job through the member API. Activation sends the initial challenge to the selected email method and returns the job record to the owning application. The application must pass the job UUID to the intended recipient flow through a trusted channel. The recipient receives the service-generated proof code or proof-token secret by email.

Proof routes do not require a Bearer token. Their access boundary is the specific active job and its current challenge; they do not create a general principal session.

Inspect the current proof state

/v1/proof/get requires the job ID. It returns masked contact methods and the current challenge's kind, status, and expiry without returning the secret:

curl -sS https://api.post.m7.org/v1/proof/get \
  -H 'Content-Type: application/json' \
  -d '{
    "job": "JOB_UUID",
    "kind": "code"
  }'

Omitting kind selects code. Use kind: "token" when the job was armed with a proof-token secret.

Verify or consume a code

/verify checks the code and marks it verified without completing the job. /consume checks the code, consumes it, marks the email method verified, and completes the job. Most integrations should consume when successful:

curl -sS https://api.post.m7.org/v1/proof/consume \
  -H 'Content-Type: application/json' \
  -d '{
    "job": "JOB_UUID",
    "kind": "code",
    "secret": "123456"
  }'

code is an accepted alias for secret when the selected kind is code.

Verify or consume a proof-token secret

Use the same routes with kind: "token":

curl -sS https://api.post.m7.org/v1/proof/consume \
  -H 'Content-Type: application/json' \
  -d '{
    "job_id": "JOB_UUID",
    "kind": "token",
    "secret": "PROOF_TOKEN"
  }'

token is an accepted alias for secret and also selects the token kind when kind is omitted. This proof-token secret is unrelated to an M7 access token and must never be sent in the Authorization header.

Resend and terminal states

/v1/proof/send requires the job ID and an eligible method_id returned by the proof state. It generates and emails a new challenge. Do not supply secret, code, or token to this route.

Issuing a new challenge revokes the previous active challenge and makes the selected method current. A successful consume completes the job and revokes sibling active credentials. Expired, consumed, revoked, or replaced credentials cannot be refreshed or reused; send a new challenge while the job is active, or have the owning application start a new job after a terminal state.

Access-token expiry, refresh, and revocation

  • Stop using an access token when its reported lifetime ends. Obtain a new token or refresh package through M7 SSO; this API does not extend token lifetimes.
  • Send refresh tokens and their binding_chain and binding_link values only to the issuing M7 SSO token endpoint with the owning OAuth client's required authentication.
  • Revoke an eligible credential through M7 SSO and discard every local copy. api.post.m7.org validates access-token JWTs locally and does not perform online introspection for each request, so clients must not keep using a revoked token while waiting for its signed lifetime to end.
  • Disabling or restricting the local principal can deny later member requests even while the JWT remains cryptographically valid.

Common failures

Member authorization failures use HTTP 401 for a missing principal and HTTP 403 for other access denials. The JSON body has status: 0, a numeric code, a diagnostic comment, and a machine-oriented reason.

Failure Typical cause Client action
Missing token with reason: "missing_principal" The Bearer header is absent Add a valid M7 access token to the Authorization header.
Invalid token with reason: "missing_principal" The JWT is malformed, expired, has an invalid signature, or fails issuer or certificate validation Discard it and obtain a new access token through M7 SSO.
principal_role_denied The active principal does not have an allowed member role Use an authorized principal; do not retry with another resource ID.
Principal inactive or unavailable The token identity does not resolve to an active local principal Reauthenticate; if the failure persists, restore the principal instead of retrying blindly.
Invalid job or Job not found The proof request has a malformed or unknown job UUID Use the exact job ID supplied by the owning application.
Job is not active or Job does not support proof The job is draft, completed, failed, cancelled, or uses proof_policy: "none" Stop the proof attempt and return to the owning application.
Proof challenge is not armed The selected kind has no current active, unexpired challenge Inspect the proof state and resend if the job remains active.
Credential not found The code or proof-token secret is incorrect Ask the recipient to re-enter the current delivered secret; do not expose which part mismatched.
Forced secret is not allowed on send A resend request included secret, code, or token Remove the secret and let the service generate the replacement.

Security checklist

  • Use TLS and the exact https://api.post.m7.org production host.
  • Keep access tokens, proof job IDs, proof secrets, refresh packages, and OAuth client secrets out of source control, logs, analytics, URLs, and error reports.
  • Store long-lived OAuth material in an application-owned secure store.
  • Share a proof job ID only with the intended recipient flow; possession can inspect masked state and trigger a resend.
  • Accept a proof secret only in the JSON request body over HTTPS. Never place it in a link, query string, cookie, or authorization header.
  • Treat challenge.expires_at and terminal job state as authoritative. Do not retry expired, consumed, revoked, or replaced credentials.
  • Use API responses and current local authorization state for access decisions; do not authorize from decoded JWT claims in client code.

Related documentation: