CodamAIDocs
Topicdone

401, 403 or 404?

The three codes that are mixed up most often, as a decision path: when to renew, when to give up, when the object is invisible.

Variants
401: token invalid or expired403 without a token403 from the tenant check403: role missing404: object missing or invisible404: path unknownOrder of role and visibility

What this is about

Three codes look alike, but they call for completely different reactions from the client:

  • 401: Your token is no good. Get a new one.
  • 403: You are known, but you may not do this. Or you did not send a token at all.
  • 404: The object does not exist for you. It may exist, but you may not see it.

The three compared

401, 403 and 404
401
who are you?
  • only comes from the filter chain
  • token expired, broken or wrongly signed
  • no body, header WWW-Authenticate: Bearer error="invalid_token"
  • CDMS never saw the request
403
you may not do this
  • no token: filter chain, body without messageKey
  • tenant refused: filter chain, error with cias.authentication.…
  • role missing: CDMS, missing-permission|<role>
  • applies equally to all objects of a model
404
does not exist for you
  • object missing or invisible: not-found…, missing-object|…
  • singleton not created yet: no-data-exists|use-create
  • path unknown: no messageKey
  • never reveals whether someone else's object exists

The decision path

flowchart TB
    S{"Status?"} -->|401| R["Renew the token,<br/>retry the request once"]
    R --> R2{"401 again?"}
    R2 -->|yes| L["log in again"]
    S -->|403| K{"Body?"}
    K -->|"no messageKey,<br/>no error"| H["check the Authorization header,<br/>log in"]
    K -->|"error: cias.authentication.…"| M["check the tenant:<br/>organization, tenant header"]
    K -->|"messageKey"| P["role missing:<br/>hide the action, show a hint"]
    S -->|404| N{"messageKey?"}
    N -->|"no"| U["wrong path:<br/>check model path and endpoint"]
    N -->|"no-data-exists…"| C["create the singleton"]
    N -->|"not-found, missing-object"| G["treat as deleted:<br/>remove from the list, go back"]

In which order CDMS checks

If both apply, i.e. the role is missing and the object is invisible: which code comes then? That depends on the operation.

Role or visibility first?

When: POST /read/{id}, GET /read/{id}

  1. 1
    CDMS
    checks the read role
  2. 2
    CDMS
    role missing → 403 missing-permission|<read role>
  3. 3
    CDMS→Database
    reads the row with all filters, no row → 404 not-found

Result: Without the read role you get 403, whether the object exists or not.

When: PUT, PATCH, DELETE, POST /{id}/rollback/{revision}

  1. 1
    CDMS→Database
    counts the row with the same filters as when reading
  2. 2
    CDMS
    invisible or not present → 404 not-found|<Dto>|<id>
  3. 3
    CDMS
    visible, role missing → 403

Result: When writing, visibility comes first. So even a missing permission reveals nothing about other people's objects.

When: The installation runs with STRICT_MODE=false.

Reading by id without the read role then returns 404 not-found instead of 403. Writing stays at 403, just with a different key, such as missing-update-role.

Result: See Strict mode.

The full table per operation is in Why invisible objects return 404.

Client reaction per code

What the client should do
StatusBodyReaction
401emptyRenew the token, retry the request once. If renewing fails or 401 comes again: log in again.
403empty or without messageKeyThe request had no token. Check the header Authorization: Bearer <token>, otherwise log in.
403error with cias.authentication.… (for a download with access_token in the messageKey)Tenant cannot be determined, is not served or is missing. Do not retry, check the organization or the tenant selection.
403missing-permission|<role> and othersRole missing. Hide the action or show a hint. Do not retry.
404not-found…, missing-object|…The object is gone or invisible. Remove it from the view, go back to the list. Do not retry.
404no-data-exists|use-createThe singleton does not exist yet. Create it with create.
404without messageKeyThe path does not exist. Check model path and endpoint in the code.

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CIAS/cias-authentication – SessionConfig (Http403ForbiddenEntryPoint, oauth2ResourceServer), JwtSessionFilter.refuse, RequestAdmission
  • CIAS/cias-runtime – SecurityChainEndToEndTest (403 without a token, 401 for an invalid token)
  • CDMS/cdms-authorization – MissingPermissionException
  • CDMS/cdms-system-layer – AbstractSystemLayer (readObject, updateObject, patchObject, deleteObject, historyRollback), AbstractLayer.assertVisibleForWrite
  • CDMS/cdms-commons – EntityNotFoundException, ApiNotFoundException
  • CDMS/cdms-rest-api – CdmsExceptionMapper, QueryTokenAuthentication
  • documentation/05-api-guide/10-fehler.md
Search