clearances
Security clearances and mandatory access control: classification schemes, adjudicated clearances, and labels that every decision enforces.
Security clearances and mandatory access control: classification schemes, adjudicated clearances, and labels that
every decision enforces. A tenant defines a scheme of ranked levels, compartments, and dissemination controls (NOFORN
and REL TO); officers grant people, service accounts, and agents a clearance and read them into compartments; and
resources carry IAM-held labels. At decision time every party of the session must dominate a resource's label, or the
decision is refused (CLEARANCE_REQUIRED, shown to callers as ACCESS_DENIED) before any role or policy is read:
the Bell-LaPadula "no read up" rule. The group needs the deployment's clearances option and answers
FEATURE_DISABLED (403) for every method without it. The guide is
Security clearances.
Schemes, clearances, and labels
The scheme in force for a tenant is the one defined closest to the root of its ancestry, so an organization's scheme
applies to all its projects and a platform scheme to every tenant. A scheme has 2 to 20 levels with ranks from 0, up
to 200 compartments with opaque ids (names can be sensitive, so audit events and emails only ever carry ids), owner
countries (alpha-3), and the caveats labels may use. Its settings say which resource types must carry a label
(requireLabels, * for every application type), an optional defaultLabel for those, the level guests count at
most (guestCeiling), whether interim clearances count, and the adjudication mode.
A clearance (one per identity, in the identity's tenant) counts at decision time only while the identity is active,
the record was issued under the scheme in force, its status is active (or interim where the scheme allows it), and
it has not reached expiresAt. A read-in counts while its NDA acceptance (when it names an
agreement) is current. Citizenship comes only from the adjudicated record, never
from identity attributes.
A label is { level, compartments?, noforn?, releasableTo? }. The label a decision applies joins the resource's own
IAM label, the labels its managed ancestors pass down (inheritToChildren, 16 levels at most), and the
classification your resolveResource returns, which can therefore only raise it. Labels outlive their resources.
iam:* actions are never subject to labels, so administration always works.
Who may call what
Officers hold iam:clearances:adjudicate (and iam:clearances:suspend for incidents) on iam/clearances/{identityId};
security administrators iam:classifications:manage on iam/classifications/scheme, and iam:classifications:label
or iam:classifications:declassify on iam/classifications/labels/{type}/{id}; reviewers iam:clearances:read.
Changes that widen access (defineScheme, updateScheme, grant, update, readIn, reinstate, revoke,
declassify) also need a recent sign-in; suspend and debrief do not. Nobody adjudicates their own clearance,
owners and root included, nor that of anyone acting in their session (an agent cannot adjudicate its sponsor). Guests
never adjudicate, and nothing that changes clearances or labels works while impersonating
(IMPERSONATION_RESTRICTED).
Under within-own adjudication (the default) an officer grants, updates to, and reinstates only levels their own
clearance holds, and reads people only into compartments they are read into themselves. While nobody in the scheme's
subtree holds an active clearance at a level (or is read into a compartment), an owner of the tenant in their own
session or a root administrator may grant it anyway: a bootstrap, audited with bootstrap: true. unrestricted
adjudication drops the rule.
| Method | What it does | Access |
|---|---|---|
debrief | Ends one read-in. | Credential |
declassify | Lowers, changes, or removes a resource's label, with a reason. | Credential |
defineScheme | Defines the tenant's classification scheme from a template or a definition of your own. | Credential |
explain | Tells an officer whether a person may read a resource and, if not, which dimension of the label they fail. | Credential |
get | Returns one identity's clearance as officers see it, or null. | Credential |
getLabel | Returns a resource's own IAM label and what it inherits from its managed parents. | Credential |
getScheme | Returns the classification scheme in force for a tenant and where it is defined, or null. | Credential |
grant | Grants an identity a clearance under the scheme in force: a level, adjudicated citizenship, and optional dates. | Credential |
label | Labels a resource or raises its label; lowering any part of a label is a declassification. | Credential |
list | Lists the tenant's clearances by person name, optionally by status, level, or end. | Credential |
listLabels | Lists the tenant's IAM labels, optionally of one resource type or level. | Credential |
mine | Returns the caller's own clearance under the scheme in force, with the scheme's levels. | Credential |
readIn | Reads a person into a compartment of the scheme, optionally backed by a non-disclosure agreement. | Credential |
reinstate | Lifts a suspension, back to the active or interim status the clearance had. | Credential |
revoke | Revokes a clearance for cause and debriefs every compartment. | Credential |
suspend | Takes a clearance out of force at once, for an incident or an investigation. | Credential |
templates | Lists the built-in schemes a tenant can start from: us, uk, nato, and corporate. | Credential |
update | Changes a live clearance's level, citizenship, interim status, investigation, or dates. | Credential |
updateScheme | Changes the scheme the tenant defines: its settings, or its definition within rules that keep what is in use. | Credential |
debrief
Ends one read-in.
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}. - Audited as:
iam:clearances:adjudicate, plusclearance:debriefwith the compartment id and the reason. - Errors:
NOT_FOUNDwhen the person is not read into the compartment or is not in this tenant;ACCESS_DENIEDfor a guest officer;INVALID_INPUTfor areasonover 512 characters;IMPERSONATION_RESTRICTED.
Debriefing only takes access away, so it needs no recent sign-in, works on your own clearance and on a suspended one, and is never blocked by an "expect allow" access invariant.
Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/debrief" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>",
"compartmentId": "<compartmentId>"
}'iam.api.clearances.debrief(
credential: CredentialInput,
input: {
tenantId: string;
identityId: string;
compartmentId: string;
reason?: string;
},
): Promise<ClearanceView>declassify
Lowers, changes, or removes a resource's label, with a reason.
- Permission:
iam:classifications:declassifyoniam/classifications/labels/{type}/{id}, and a recent sign-in. - Audited as:
iam:classifications:declassify, plusclassification:declassifywith the label before and after (orremoved: true) and the reason. - Errors:
ACCESS_DENIED(audited) when your own clearance does not dominate the current label, or for a guest officer;NOT_FOUNDwhen the resource has no label or no scheme applies;INVALID_INPUTwithoutlabel(passnullto remove it) orreason, or for a label the scheme cannot read;IMPERSONATION_RESTRICTED;RECENT_AUTH_REQUIRED.
Nobody declassifies what they could not read, as the scheme in force reads the label, even one written under another
scheme. Only a label naming a level, compartment, or caveat the scheme in force does not define, which no clearance can
dominate, may be repaired by anyone with the permission. inheritToChildren: false stops a label passing down.
Prop
Type
One of null | ResourceLabelView; the object form has these fields:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/declassify" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"type": "<type>",
"id": "<id>",
"label": {
"level": "<level>"
},
"reason": "<reason>"
}'iam.api.clearances.declassify(
credential: CredentialInput,
input: {
tenantId: string;
type: string;
id: string;
label: ClassificationLabel | null;
reason: string;
inheritToChildren?: boolean;
},
): Promise<ResourceLabelView | null>defineScheme
Defines the tenant's classification scheme from a template or a definition of your own.
Used inSecurity clearances
- Permission:
iam:classifications:manageoniam/classifications/scheme, and a recent sign-in. - Audited as:
iam:classifications:manage, plusclassification:scheme-definewith the template, level and compartment ids, and the settings. - Errors:
CONFLICT(409) when the tenant, an ancestor, or a tenant below it already defines one;INVALID_INPUTwithout exactly one oftemplateanddefinition, for an unknown template, a definition that does not validate (levels, ranks, ids, names, compartments, countries, caveats, NOFORN without an owner country), a missingnameor one over 100 characters, more than 100requireLabelsor a platform type among them, adefaultLabelinvalid for the definition, aguestCeilingthat is not a level, an unknownadjudication, or more than 20notify.emails;RECENT_AUTH_REQUIRED.
Settings default to no required labels, no default label, no guest clearances (guestCeiling: null), no interim
clearances, and within-own adjudication. Decisions in the tenant and every tenant below it apply the scheme from the
next request.
await iam.api.clearances.defineScheme(credential, {
tenantId,
name: 'Acme classification',
template: 'us',
requireLabels: ['document'],
guestCeiling: 'C',
interimAllowed: true,
});Prop
Type
A ClassificationSchemeView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/defineScheme" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"name": "<name>",
"tenantId": "<tenantId>"
}'iam.api.clearances.defineScheme(
credential: CredentialInput,
input: ClassificationSchemeInput & { tenantId: string },
): Promise<ClassificationSchemeView>explain
Tells an officer whether a person may read a resource and, if not, which dimension of the label they fail.
Used inSecurity clearances
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}. - Audited as:
iam:clearances:adjudicate. - Errors:
NOT_FOUNDwhen no scheme applies or the identity is not in this tenant.
Decisions only ever say CLEARANCE_REQUIRED, and audit events only { mandatory: 'clearance' }. explain is the one
place that names the failure: level, compartment, noforn, releasability, or invalid-label (also for a
missing required label), with the label decisions apply (after inheritance, the resolver, and the default) and the
clearance of every party of the person's own sessions (an agent with its sponsor). It works for resources that no
longer exist, since their labels remain.
const why = await iam.api.clearances.explain(credential, {
tenantId,
identityId: alice.id,
type: 'document',
id: 'q3-plan',
});
// { allowed: false, failure: 'compartment', label: { level: 'S', compartments: ['LANTERN'] }, party, parties }Prop
Type
A ClearanceExplanation object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/explain" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>",
"type": "<type>",
"id": "<id>"
}'iam.api.clearances.explain(
credential: CredentialInput,
input: { tenantId: string; identityId: string; type: string; id: string },
): Promise<ClearanceExplanation>get
Returns one identity's clearance as officers see it, or null.
- Permission:
iam:clearances:readoniam/clearances/{identityId}. - Audited as:
iam:clearances:read. - Errors:
NOT_FOUNDwhen the identity is not in this tenant.
Besides the stored record, the view reports effectiveStatus and effectiveLevel (what decisions count right now:
none, expired, a guest's capped level), compartment names, and whether each read-in is current.
Prop
Type
One of null | ClearanceView; the object form has these fields:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/get" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>"
}'iam.api.clearances.get(
credential: CredentialInput,
input: { tenantId: string; identityId: string },
): Promise<ClearanceView | null>getLabel
Returns a resource's own IAM label and what it inherits from its managed parents.
- Permission:
iam:clearances:readoniam/classifications/labels/{type}/{id}. - Audited as:
iam:clearances:read. - Errors:
NOT_FOUNDwhen no scheme applies;INVALID_INPUTfor a platform type.
label is null when the resource has none of its own, and inherited is the join of the labels its managed ancestors
pass down, the labels of the same model in the tenants above, and, for an SSH login, its host's label. A label your
resolver returns is applied by decisions but is not shown here; use explain for
the label a decision applies.
Prop
Type
A ResourceLabelState object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/getLabel" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"type": "<type>",
"id": "<id>"
}'iam.api.clearances.getLabel(
credential: CredentialInput,
input: { tenantId: string; type: string; id: string },
): Promise<ResourceLabelState>getScheme
Returns the classification scheme in force for a tenant and where it is defined, or null.
- Permission:
iam:clearances:readoniam/classifications/scheme. - Audited as:
iam:clearances:read.
tenantId in the result is the defining tenant, and inherited is true when an ancestor defines it (change it there).
The result carries the definition with compartment names, the settings, and the version that
updateScheme takes.
Prop
Type
One of null | ClassificationSchemeView; the object form has these fields:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/getScheme" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.clearances.getScheme(
credential: CredentialInput,
input: { tenantId: string },
): Promise<ClassificationSchemeView | null>grant
Grants an identity a clearance under the scheme in force: a level, adjudicated citizenship, and optional dates.
Used inSecurity clearances
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}, and a recent sign-in. - Audited as:
iam:clearances:adjudicate, plusclearance:grantwith the level, status, end, andbootstrap. - Errors:
CONFLICT(409) when the identity already holds a live (interim, active, or suspended) clearance;ACCESS_DENIEDfor your own clearance or that of a party of your session, for a guest officer, and underwithin-ownfor a level beyond your own clearance (all audited);INVALID_INPUTfor an identity that is not active, an unknown level, a guest above the scheme's guest ceiling (or under a scheme without one),interimwhere the scheme does not allow it, more than 10 or malformedcitizenshipcodes, a malformedinvestigation, anexpiresAtthat is not in the future, or dates more than twenty years ahead;NOT_FOUNDwhen no scheme applies or the identity is not in this tenant;IMPERSONATION_RESTRICTED;RECENT_AUTH_REQUIRED.
People, service accounts, and agents can hold clearances; an agent's key reads a label only when the agent and its sponsor both dominate it. A revoked or terminated record is replaced by a new grant (the audit trail keeps the history). The person learns nothing by email; their access changes from the next request.
await iam.api.clearances.grant(credential, {
tenantId,
identityId: alice.id,
level: 'S',
citizenship: ['USA'],
investigation: { kind: 'T5', completedAt: Date.parse('2026-08-01') },
reinvestigationDue: Date.parse('2031-08-01'),
});A ClearanceGrantInput object:
Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/grant" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>",
"level": "<level>",
"citizenship": [
"<citizenship>"
]
}'iam.api.clearances.grant(
credential: CredentialInput,
input: ClearanceGrantInput,
): Promise<ClearanceView>label
Labels a resource or raises its label; lowering any part of a label is a declassification.
Used inSecurity clearances
- Permission:
iam:classifications:labeloniam/classifications/labels/{type}/{id}. - Audited as:
iam:classifications:label, plusclassification:labelwith the type, level, compartment ids, caveats,inheritToChildren, and the previous level. - Errors:
ACCESS_DENIED(audited) when the new label does not cover the current one in every dimension, would turn inheritance off, or replaces a label written under another scheme (usedeclassify);INVALID_INPUTfor a label the scheme cannot read (unknown level or compartment, a caveat the scheme does not use, a malformed country), a platform type, or atypethat is not a resource type name (a lowercase letter, then lowercase letters, digits, or-);NOT_FOUNDwhen no scheme applies;IMPERSONATION_RESTRICTED.
The resource need not exist yet, and the label outlives it, so deleting and recreating a resource never declassifies
it; a registered resource deleted while it inherits a label keeps that label as its own. With
inheritToChildren: true the label also applies to every managed descendant. Labeling the same label again changes
nothing and records no classification:label event.
await iam.api.clearances.label(credential, {
tenantId,
type: 'document',
id: 'q3-plan',
label: { level: 'S', compartments: ['LANTERN'], noforn: true },
});Prop
Type
A ResourceLabelView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/label" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"type": "<type>",
"id": "<id>",
"label": {
"level": "<level>"
}
}'iam.api.clearances.label(
credential: CredentialInput,
input: {
tenantId: string;
type: string;
id: string;
label: ClassificationLabel;
inheritToChildren?: boolean;
},
): Promise<ResourceLabelView>list
Lists the tenant's clearances by person name, optionally by status, level, or end.
- Permission:
iam:clearances:readoniam/clearances. - Audited as:
iam:clearances:read. - Errors:
INVALID_INPUTfor an unknownstatus, anexpiringWithinDaysoutside 1 to 3650, alimitoutside 1 to 500, or anoffsetoutside 0 to 1000000.
status filters by the stored status, level by level id, and expiringWithinDays keeps clearances whose
expiresAt falls within that many days (ended ones included). total counts every match before paging with limit
(100 by default) and offset.
Prop
Type
A ClearancePage object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/list" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.clearances.list(
credential: CredentialInput,
input: {
tenantId: string;
status?: ClearanceStatus;
level?: string;
expiringWithinDays?: number;
limit?: number;
offset?: number;
},
): Promise<ClearancePage>listLabels
Lists the tenant's IAM labels, optionally of one resource type or level.
- Permission:
iam:clearances:readoniam/classifications/labels. - Audited as:
iam:clearances:read. - Errors:
INVALID_INPUTfor a platform type, alimitoutside 1 to 500, or anoffsetoutside 0 to 1000000.
Labels are ordered by type and resource id; total counts every match before paging with limit (100 by default)
and offset. Each carries the level name when the scheme still has the level.
Prop
Type
A ResourceLabelPage object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/listLabels" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.clearances.listLabels(
credential: CredentialInput,
input: {
tenantId: string;
type?: string;
level?: string;
limit?: number;
offset?: number;
},
): Promise<ResourceLabelPage>mine
Returns the caller's own clearance under the scheme in force, with the scheme's levels.
- Permission: None beyond the caller's own session or API key in the tenant.
- Audited as: Not audited; it only reads.
- Errors:
ACCESS_DENIEDfrom a role session, session token, delegated session, or a session of another tenant;IMPERSONATION_RESTRICTEDwhile impersonating.
The result is { scheme, clearance }: the scheme's name and levels (null when no scheme applies), and the caller's
level, status, effective status, citizenship, dates, and read-ins with current: false for those whose NDA still needs
accepting (null when they hold no clearance). It backs a "my clearance" page.
Prop
Type
A MyClearance object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/mine" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.clearances.mine(
credential: CredentialInput,
input: { tenantId: string },
): Promise<MyClearance>readIn
Reads a person into a compartment of the scheme, optionally backed by a non-disclosure agreement.
Used inSecurity clearances
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}, and a recent sign-in. - Audited as:
iam:clearances:adjudicate, plusclearance:read-inwith the compartment id, the level, the agreement, andbootstrap. - Errors:
CONFLICT(409) when already read in, or for a clearance issued under another scheme;INVALID_TRANSITION(409) for a suspended clearance;INVALID_INPUTfor a compartment the scheme does not define or a guest;NOT_FOUNDwhen the identity holds no live clearance or the agreement is not in the person's tenant;ACCESS_DENIEDfor your own clearance and, underwithin-own, for a compartment you are not read into;IMPERSONATION_RESTRICTED;RECENT_AUTH_REQUIRED.
With agreementId, the read-in counts only while the person's acceptance of the agreement's current version is
current: a new version, a lapsed reacceptAfterDays, or deleting the agreement closes it until they accept again.
The person may accept after the read-in; acceptedAt records an acceptance that was current at the time.
await iam.api.clearances.readIn(credential, {
tenantId,
identityId: alice.id,
compartmentId: 'LANTERN',
agreementId: lanternNdaId,
});Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/readIn" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>",
"compartmentId": "<compartmentId>"
}'iam.api.clearances.readIn(
credential: CredentialInput,
input: {
tenantId: string;
identityId: string;
compartmentId: string;
agreementId?: string;
},
): Promise<ClearanceView>reinstate
Lifts a suspension, back to the active or interim status the clearance had.
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}, and a recent sign-in. - Audited as:
iam:clearances:adjudicate, plusclearance:reinstatewith the level, status, reason, andbootstrap. - Errors:
INVALID_TRANSITION(409) when the clearance is not suspended;NOT_FOUNDwhen the identity holds no live clearance;CONFLICT(409) for a clearance issued under another scheme;INVALID_INPUTwhen its level left the scheme;ACCESS_DENIEDfor your own clearance and, underwithin-own, unless your clearance holds its level and every compartment it is read into (they come back with it);IMPERSONATION_RESTRICTED;RECENT_AUTH_REQUIRED.
The person gets a clearance-status email.
Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/reinstate" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>"
}'iam.api.clearances.reinstate(
credential: CredentialInput,
input: { tenantId: string; identityId: string; reason?: string },
): Promise<ClearanceView>revoke
Revokes a clearance for cause and debriefs every compartment.
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}, and a recent sign-in. - Audited as:
iam:clearances:adjudicate, plusclearance:revokewith the level, the reason, and the debriefed compartment ids. - Errors:
NOT_FOUNDwhen the identity holds no live clearance;INVALID_INPUTwithout areason(up to 512 characters);ACCESS_DENIEDfor a guest officer;IMPERSONATION_RESTRICTED;RECENT_AUTH_REQUIRED.
The record stays as history with status revoked, through offboarding and deletion too; a new clearance needs a new
grant. The person gets a clearance-status email unless notifyPerson: false. Revoking is never blocked by
an "expect allow" access invariant.
Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/revoke" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>",
"reason": "<reason>"
}'iam.api.clearances.revoke(
credential: CredentialInput,
input: {
tenantId: string;
identityId: string;
reason: string;
notifyPerson?: boolean;
},
): Promise<ClearanceView>suspend
Takes a clearance out of force at once, for an incident or an investigation.
Used inSecurity clearances
- Permission:
iam:clearances:suspendoniam/clearances/{identityId}; no recent sign-in. - Audited as:
iam:clearances:suspend, plusclearance:suspendwith the level, the reason, and the incident. - Errors:
NOT_FOUNDwhen the identity holds no interim or active clearance;INVALID_TRANSITION(409) when it is already suspended;INVALID_INPUTwithout areason(up to 512 characters);ACCESS_DENIEDfor a guest officer;IMPERSONATION_RESTRICTED.
Every decision from the next request treats the person as uncleared. Pass the incident's id as incidentId. The person
gets a clearance-status email unless notifyPerson: false (an investigation that must not tip them off). Only
reinstate lifts a suspension.
await iam.api.clearances.suspend(credential, {
tenantId,
identityId: bob.id,
reason: 'Under investigation',
incidentId,
notifyPerson: false,
});Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/suspend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>",
"reason": "<reason>"
}'iam.api.clearances.suspend(
credential: CredentialInput,
input: {
tenantId: string;
identityId: string;
reason: string;
incidentId?: string;
notifyPerson?: boolean;
},
): Promise<ClearanceView>templates
Lists the built-in schemes a tenant can start from: us, uk, nato, and corporate.
- Permission: None beyond a valid credential.
- Audited as: Not audited.
- Errors:
FEATURE_DISABLED(403) without theclearancesoption;UNAUTHENTICATED.
Each entry is { id, name, definition }. Compartments are always empty: add your own after defining the scheme. The
same definitions are exported as classificationTemplates from better-iam/core.
An array of ClassificationTemplateView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/templates" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{}'iam.api.clearances.templates(
credential: CredentialInput,
): Promise<ClassificationTemplateView[]>update
Changes a live clearance's level, citizenship, interim status, investigation, or dates.
- Permission:
iam:clearances:adjudicateoniam/clearances/{identityId}, and a recent sign-in. - Audited as:
iam:clearances:adjudicate, plusclearance:updatewith the level, the previous level, the status, and the changed fields (none when nothing changed). - Errors:
NOT_FOUNDwhen the identity holds no live clearance;CONFLICT(409) for a clearance issued under another scheme (revoke it and grant a new one);ACCESS_DENIEDas forgrant, applied to the higher of the old and the new level;INVALID_INPUTas forgrant, or when the clearance's level left the scheme and no newlevelis given;IMPERSONATION_RESTRICTED;RECENT_AUTH_REQUIRED.
null clears investigation, reinvestigationDue, and expiresAt. interim: false makes an interim clearance final.
Changing a suspended clearance keeps it suspended (an interim change applies when it is reinstated).
A ClearanceUpdateInput object:
Prop
Type
A ClearanceView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/update" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"identityId": "<identityId>"
}'iam.api.clearances.update(
credential: CredentialInput,
input: ClearanceUpdateInput,
): Promise<ClearanceView>updateScheme
Changes the scheme the tenant defines: its settings, or its definition within rules that keep what is in use.
Used inSecurity clearances
- Permission:
iam:classifications:manageoniam/classifications/scheme, and a recent sign-in. - Audited as:
iam:classifications:manage, plusclassification:scheme-updatewith the changed field names, the new version and, for a new definition, the level, compartment, and owner country ids. - Errors:
NOT_FOUNDwhen no scheme applies;CONFLICT(409) when an ancestor defines the scheme in force;VERSION_CONFLICT(409) whenversionis not the stored one;RESOURCE_IN_USE(409) when the new definition re-ranks any level (labels your resolver asserts or adefaultLabelmay use any level, so none is ever re-ranked, and one removed earlier comes back only at the rank it had), removes a level that a live clearance or a label uses, removes a compartment in use, or would make a label invalid;INVALID_INPUTfor atemplate, new levels that do not rank above every kept level, a definition or setting that does not validate, or a keptdefaultLabelthe new definition cannot read;RECENT_AUTH_REQUIRED.
Only the fields you pass change; null clears defaultLabel and notify. Settings such as requireLabels,
guestCeiling, and interimAllowed take effect on the next decision. Adding an owner country widens who reads NOFORN
material.
const scheme = (await iam.api.clearances.getScheme(credential, { tenantId }))!;
await iam.api.clearances.updateScheme(credential, {
tenantId,
version: scheme.version,
definition: { ...scheme.definition, compartments: [{ id: 'LANTERN', name: 'Project Lantern' }] },
});Prop
Type
A ClassificationSchemeView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/clearances/updateScheme" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.clearances.updateScheme(
credential: CredentialInput,
input: Partial<ClassificationSchemeInput> & { tenantId: string; version?: number },
): Promise<ClassificationSchemeView>Better IAM is created by Sean Filimon
Last updated