# `AttestoPhoenix.PrincipalStore`
[🔗](https://github.com/XukuLLC/attesto_phoenix/blob/v0.19.0/lib/attesto_phoenix/principal_store.ex#L1)

The host-owned subject/principal contract.

The library resolves the subject during protected-resource authentication
and builds the principal map minted into issued tokens, but the subject
source (the host's user store) and the claim shaping are host policy. A host
implements this behaviour and wires each callback into
`AttestoPhoenix.Config`; this module is the contract those keys install and
the recommended production shape.

Each `@callback` corresponds to the identically named `AttestoPhoenix.Config`
key:

  * `load_principal/1` (`:load_principal`, required)
  * `build_principal/3` (`:build_principal`)
  * `resolve_jwt_bearer_subject/1` (`:resolve_jwt_bearer_subject`, required only
    when the ID-JAG `jwt-bearer` grant is enabled)

# `principal`

```elixir
@type principal() :: term()
```

The host's opaque principal/subject representation.

# `build_principal`
*optional* 

```elixir
@callback build_principal(
  client :: term(),
  subject :: String.t(),
  scope :: [String.t()]
) :: map()
```

Build the principal map passed to `Attesto.Token.mint/3` for an
authorization-code or `client_credentials` grant. Receives the resolved
client, the subject identifier, and the granted scope. The returned map
carries at least `:sub` and any host-owned claims.

The returned `:sub` MUST be namespaced with the matching
`Attesto.PrincipalKind` `sub_prefix` - `Attesto.Token` rejects an unprefixed
subject at mint time (`:invalid_sub`). For the `client_credentials` grant
(RFC 6749 §4.4) the subject handed in is the OAuth `client_id`, and Dynamic
Client Registration (RFC 7591 §3.2.1) issues that id *unprefixed*: this
callback is the sole place the kind prefix is applied. The prefix is mint-time
defense-in-depth (a token's `sub` stays unambiguous across principal kinds),
so namespacing here is mandatory rather than cosmetic.

# `load_principal`

```elixir
@callback load_principal(subject_id :: String.t()) ::
  {:ok, principal()} | {:error, :not_found}
```

Resolve the subject/principal by its identifier during protected-resource
authentication. Returns `{:ok, principal}` or `{:error, :not_found}`.

# `resolve_jwt_bearer_subject`
*optional* 

```elixir
@callback resolve_jwt_bearer_subject(claims :: map()) ::
  {:ok, subject :: String.t()} | String.t() | {:error, term()}
```

Map a validated Identity Assertion JWT Authorization Grant (ID-JAG) to a local
subject for the `urn:ietf:params:oauth:grant-type:jwt-bearer` grant
(`draft-ietf-oauth-identity-assertion-authz-grant-04`).

Receives the string-keyed, already-verified assertion claims (the signature,
trusted `iss`, `aud`, `client_id` binding, `exp`/`iat`, and `jti` replay have
all been checked). The host maps the asserted external identity - typically
`claims["sub"]` (unique when scoped with `claims["iss"]`) and/or
`claims["email"]` - to the local subject the issued token is minted for, the
same subject string `build_principal/3` then receives.

Returns `{:ok, subject}` (or a bare `subject` string) to authorize, or
`{:error, reason}` (or any non-subject value) to deny - a deny becomes
RFC 6749 §5.2 `invalid_grant`. Required only when the `jwt-bearer` grant is
enabled (`AttestoPhoenix.Config` enforces this at boot).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
