You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(be): OpenIdCredentialKey with data migration — add aud for SSO security (dfinity#3784)
## Summary
Add the `aud` (audience / client_id) field to `OpenIdCredentialKey`,
changing it from `(iss, sub)` to `(iss, sub, aud)`. This is a security
prerequisite for SSO: since SSO allows anyone to provide a `client_id`
via their `ii-openid-configuration` endpoint, without `aud` in the key
two different OIDC clients at the same provider with the same user `sub`
would collide, enabling impersonation.
## Changes
- **Type update**: `OpenIdCredentialKey` type alias changed from `(Iss,
Sub)` to `(Iss, Sub, Aud)` in both `internet_identity_interface` and the
`openid` module
- **CBOR encoding**: `StorableOpenIdCredentialKey` rewritten with manual
`Encode`/`Decode` impls — new entries use CBOR map format `{0:iss,
1:sub, 2:aud}`; the decoder also handles legacy CBOR array format `[iss,
sub]` for backward compatibility
- **Migration**: `post_upgrade` drains the credential key index via
`pop_first`, resolves `aud` from each anchor's
`StorableOpenIdCredential` (which already stores `aud` at CBOR index
`#[n(2)]`), and re-inserts with the complete `(iss, sub, aud)` key.
Unresolvable entries are preserved with empty `aud` for retry on next
upgrade.
- **Key construction**: Updated `OpenIdCredential::key()`,
`StorableOpenIdCredential::key()`, `calculate_delegation_seed()`, and
all call sites
- **Candid interface**: Updated `.did` file and generated JS/TS
declarations
- **Frontend**: Updated credential removal call to pass `aud`
- **Tests**: Added unit tests for new CBOR map encoding, legacy array
decoding, and round-trip serialization. Updated existing test assertions
to use 3-tuple keys.
## Delegation seed backward compatibility
The `calculate_delegation_seed` function already receives `client_id`
(which equals `aud`) as a separate parameter. The seed calculation is
unchanged — `aud` from the key tuple is ignored (`_aud`) in the
destructuring, preserving identical `Principal` derivation for existing
credentials.
## Migration safety
- Uses `pop_first()` to drain the BTreeMap, avoiding byte-level encoding
mismatches between legacy array-encoded keys and new map-encoded keys
- Resolves `aud` from the anchor's stored `StorableOpenIdCredential`
which already has `aud` at CBOR index 2
- Falls back to re-inserting with empty `aud` if resolution fails, with
a logged warning — the entry is preserved for retry on next upgrade
- Idempotent: safe to run on every upgrade; entries already in the new
format are preserved unchanged
## Test plan
- [x] All 209 unit tests pass (including Candid interface compatibility)
- [ ] Integration tests (require canister WASM build — pass in CI)
- [ ] Deploy to testnet and verify migration of existing credentials
- [ ] Verify credential lookup works after migration
- [ ] Verify new credential registration includes `aud` in key
---
[< Previous PR](dfinity#3778)
| [Next PR >](dfinity#3785)
---------
Co-authored-by: Claude Agent <noreply@anthropic.com>
Co-authored-by: Arshavir Ter-Gabrielyan <arshavir.ter.gabrielyan@dfinity.org>
0 commit comments