Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
05514b2
feat(be): mint short-lived app delegations from a session
sea-snake Aug 22, 2026
ef6bb0b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Aug 25, 2026
daa9a72
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Aug 25, 2026
83e7b6f
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Aug 25, 2026
fa2de80
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Aug 31, 2026
a253830
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Aug 31, 2026
1725b03
merge: carry the unit rename into the mint path
sea-snake Aug 31, 2026
94a52eb
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Aug 31, 2026
c0cb41b
merge: one predicate, and a default idle bound
sea-snake Aug 31, 2026
26a80cd
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 1, 2026
0aaa753
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 1, 2026
10b4941
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 1, 2026
d315767
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 1, 2026
4b27570
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 1, 2026
fe3f2c4
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 2, 2026
99c2ce0
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
9e53312
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
3d585f5
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
eae2ca4
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
4a13814
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
283966b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
3625133
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 4, 2026
d354493
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
8d78bea
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
69de220
refactor(be): resolve a principal to an account address, not a stored…
sea-snake Sep 5, 2026
3a4dd47
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
b7194c6
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
ee59fd5
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
002d4f4
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
98ad58b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
de8b8f9
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
38f2a89
test: a browser presents the successor it announced
sea-snake Sep 5, 2026
b1fe944
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
51ca118
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
a99e95d
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
5a3732b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
77ec9b6
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
6cfc1f5
chore: the session key's account has a caller now
sea-snake Sep 5, 2026
d67503c
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
6923e0b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
a37d485
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
4c392f6
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
8f07338
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
64cd420
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
71d3682
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
86e188a
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
bb73a29
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
647ea14
refactor(be): name the account reference list rather than a row
sea-snake Sep 5, 2026
eb4c244
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 5, 2026
36c01db
refactor(be): name the account reference list rather than a row
sea-snake Sep 5, 2026
799471c
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
9574cb0
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
d864b4e
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
1f8a86b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
9b7d0ad
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
1f7e350
refactor(be): a browser, not a session device
sea-snake Sep 6, 2026
c0c09c8
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
e4559de
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
d530d13
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
d20bc65
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
d8b3bd5
test(be): the request field is browser_name
sea-snake Sep 6, 2026
da98041
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
647a6f1
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
dacecd8
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
72261e3
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 6, 2026
e732621
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
116d0b4
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
9f686a4
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
26c5767
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
93c8925
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
b086c3c
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
1cafd48
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
47958a5
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
90483ff
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
4528d90
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
89b5a30
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
3d84dfe
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 7, 2026
869e615
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 8, 2026
20a7042
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 8, 2026
6ebfec9
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 8, 2026
eb1769b
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 8, 2026
44a046a
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
b98c222
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
f39368f
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
46ecf8b
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
b78e6b4
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
6e7b795
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
b06ed08
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 8, 2026
01394df
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 9, 2026
6f72e85
chore: merge feat/sign-in-creates-a-session
sea-snake Sep 9, 2026
47a3fcd
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
ca502b6
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
cff441b
chore: rename the session record accessors at their call sites
sea-snake Sep 9, 2026
1c05288
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
926c53a
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
baa46c0
refactor(session): passing the checks is a type, not a tuple
sea-snake Sep 9, 2026
b9e93ca
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
0f4b97f
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
dcc6ae6
feat(session): a wrong expiration is a missing delegation, not a miss…
sea-snake Sep 9, 2026
61be3d4
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 9, 2026
cfc7352
Merge branch 'feat/sign-in-creates-a-session' into feat/app-delegatio…
sea-snake Sep 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/canister_tests/src/api/internet_identity/api_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,3 +772,29 @@ pub fn get_account_session(
) -> Result<Result<GetAccountSessionResponse, AccountSessionError>, RejectResponse> {
query_candid_as(env, canister_id, sender, "get_account_session", (request,)).map(|(x,)| x)
}

pub fn app_prepare_delegation(
env: &PocketIc,
canister_id: CanisterId,
sender: Principal,
request: AppPrepareDelegationRequest,
) -> Result<Result<AppPrepareDelegationResponse, AppSessionError>, RejectResponse> {
call_candid_as(
env,
canister_id,
RawEffectivePrincipal::None,
sender,
"app_prepare_delegation",
(request,),
)
.map(|(x,)| x)
}

pub fn app_get_delegation(
env: &PocketIc,
canister_id: CanisterId,
sender: Principal,
request: AppGetDelegationRequest,
) -> Result<Result<SignedDelegation, AppSessionError>, RejectResponse> {
query_candid_as(env, canister_id, sender, "app_get_delegation", (request,)).map(|(x,)| x)
}
53 changes: 42 additions & 11 deletions src/frontend/src/lib/generated/internet_identity_idl.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,33 @@ export const idlFactory = ({ IDL }) => {
'device_registration_timeout' : Timestamp,
}),
});
const SessionKey = PublicKey;
const AppGetDelegationRequest = IDL.Record({
'session_key' : SessionKey,
'expiration' : Timestamp,
});
const Delegation = IDL.Record({
'permissions' : IDL.Opt(IDL.Text),
'pubkey' : PublicKey,
'targets' : IDL.Opt(IDL.Vec(IDL.Principal)),
'expiration' : Timestamp,
});
const SignedDelegation = IDL.Record({
'signature' : IDL.Vec(IDL.Nat8),
'delegation' : Delegation,
});
const AppSessionError = IDL.Variant({
'NoSuchDelegation' : IDL.Null,
'InternalCanisterError' : IDL.Text,
'NoSuchSession' : IDL.Null,
});
const AppPrepareDelegationRequest = IDL.Record({
'session_key' : SessionKey,
});
const AppPrepareDelegationResponse = IDL.Record({
'user_key' : PublicKey,
'expiration' : Timestamp,
});
const IdentityNumber = IDL.Nat64;
const AuthnMethodProtection = IDL.Variant({
'Protected' : IDL.Null,
Expand Down Expand Up @@ -358,22 +385,11 @@ export const idlFactory = ({ IDL }) => {
'nonce' : IDL.Text,
'expires_at' : Timestamp,
});
const SessionKey = PublicKey;
const EmailRecoveryGetDelegationArgs = IDL.Record({
'session_key' : SessionKey,
'expiration' : Timestamp,
'nonce' : IDL.Text,
});
const Delegation = IDL.Record({
'permissions' : IDL.Opt(IDL.Text),
'pubkey' : PublicKey,
'targets' : IDL.Opt(IDL.Vec(IDL.Principal)),
'expiration' : Timestamp,
});
const SignedDelegation = IDL.Record({
'signature' : IDL.Vec(IDL.Nat8),
'delegation' : Delegation,
});
const BufferedArchiveEntry = IDL.Record({
'sequence_number' : IDL.Nat64,
'entry' : IDL.Vec(IDL.Nat8),
Expand Down Expand Up @@ -923,6 +939,21 @@ export const idlFactory = ({ IDL }) => {
[AddTentativeDeviceResponse],
[],
),
'app_get_delegation' : IDL.Func(
[AppGetDelegationRequest],
[IDL.Variant({ 'Ok' : SignedDelegation, 'Err' : AppSessionError })],
['query'],
),
'app_prepare_delegation' : IDL.Func(
[AppPrepareDelegationRequest],
[
IDL.Variant({
'Ok' : AppPrepareDelegationResponse,
'Err' : AppSessionError,
}),
],
[],
),
'authn_method_add' : IDL.Func(
[IdentityNumber, AuthnMethodData],
[IDL.Variant({ 'Ok' : IDL.Null, 'Err' : AuthnMethodAddError })],
Expand Down
50 changes: 50 additions & 0 deletions src/frontend/src/lib/generated/internet_identity_types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,41 @@ export interface AnchorCredentials {
'credentials' : Array<WebAuthnCredential>,
'recovery_credentials' : Array<WebAuthnCredential>,
}
export interface AppGetDelegationRequest {
'session_key' : SessionKey,
/**
* Must match the prepared value.
*/
'expiration' : Timestamp,
}
export interface AppPrepareDelegationRequest {
/**
* The key the app delegation delegates to. Nothing about the account is named:
* the caller's own session chain is what identifies it.
*/
'session_key' : SessionKey,
}
export interface AppPrepareDelegationResponse {
'user_key' : PublicKey,
'expiration' : Timestamp,
}
export type AppSessionError = {
/**
* The session is live, but nothing was signed for the session_key and expiration
* asked for — so the expiration is one app_prepare_delegation never returned. Prepare
* again and use what comes back; signing in afresh is not the remedy.
*/
'NoSuchDelegation' : null
} |
{ 'InternalCanisterError' : string } |
{
/**
* No usable session behind this caller: revoked, expired, pruned, or never one at
* all. One outcome, because which of those it is depends on whether a prune has run
* yet, and because an app can act on none of them differently.
*/
'NoSuchSession' : null
};
/**
* Configuration parameters related to the archive.
*/
Expand Down Expand Up @@ -1957,6 +1992,21 @@ export interface _SERVICE {
[UserNumber, DeviceData],
AddTentativeDeviceResponse
>,
'app_get_delegation' : ActorMethod<
[AppGetDelegationRequest],
{ 'Ok' : SignedDelegation } |
{ 'Err' : AppSessionError }
>,
/**
* Mints a short-lived app delegation from a live session. Called by app frontends
* with the session chain, so revoking the session ends access within one delegation
* lifetime.
*/
'app_prepare_delegation' : ActorMethod<
[AppPrepareDelegationRequest],
{ 'Ok' : AppPrepareDelegationResponse } |
{ 'Err' : AppSessionError }
>,
/**
* Adds a new authentication method to the identity.
* Requires authentication.
Expand Down
35 changes: 35 additions & 0 deletions src/internet_identity/internet_identity.did
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,35 @@ type AccountSessionError = variant {
InternalCanisterError : text;
};

type AppPrepareDelegationRequest = record {
// The key the app delegation delegates to. Nothing about the account is named:
// the caller's own session chain is what identifies it.
session_key : SessionKey;
};

type AppPrepareDelegationResponse = record {
user_key : PublicKey;
expiration : Timestamp;
};

type AppGetDelegationRequest = record {
session_key : SessionKey;
// Must match the prepared value.
expiration : Timestamp;
};

type AppSessionError = variant {
// No usable session behind this caller: revoked, expired, pruned, or never one at
// all. One outcome, because which of those it is depends on whether a prune has run
// yet, and because an app can act on none of them differently.
NoSuchSession;
// The session is live, but nothing was signed for the session_key and expiration
// asked for — so the expiration is one app_prepare_delegation never returned. Prepare
// again and use what comes back; signing in afresh is not the remedy.
NoSuchDelegation;
InternalCanisterError : text;
};

type IdentityInfo = record {
authn_methods : vec AuthnMethodData;
authn_method_registration : opt AuthnMethodRegistrationInfo;
Expand Down Expand Up @@ -1988,6 +2017,12 @@ service : (opt InternetIdentityInit) -> {
prepare_account_session : (PrepareAccountSessionRequest) -> (variant { Ok : PrepareAccountSessionResponse; Err : AccountSessionError });
get_account_session : (GetAccountSessionRequest) -> (variant { Ok : GetAccountSessionResponse; Err : AccountSessionError }) query;

// Mints a short-lived app delegation from a live session. Called by app frontends
// with the session chain, so revoking the session ends access within one delegation
// lifetime.
app_prepare_delegation : (AppPrepareDelegationRequest) -> (variant { Ok : AppPrepareDelegationResponse; Err : AppSessionError });
app_get_delegation : (AppGetDelegationRequest) -> (variant { Ok : SignedDelegation; Err : AppSessionError }) query;

prepare_account_delegation : (
anchor_number : UserNumber,
origin : FrontendHostname,
Expand Down
14 changes: 14 additions & 0 deletions src/internet_identity/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,20 @@ fn get_account_session(
sessions::get_account_session(request)
}

#[update]
fn app_prepare_delegation(
request: AppPrepareDelegationRequest,
) -> Result<AppPrepareDelegationResponse, AppSessionError> {
sessions::app_prepare_delegation(request)
}

#[query]
fn app_get_delegation(
request: AppGetDelegationRequest,
) -> Result<SignedDelegation, AppSessionError> {
sessions::app_get_delegation(request)
}

#[update]
fn prepare_account_delegation(
anchor_number: AnchorNumber,
Expand Down
Loading
Loading