user-service API
User registration, profile management, and authentication coordination canister.
Candid file: user-service/src/user_service.did
Types
IndividualRecord
User profile data:
type IndividualRecord = record {
id: text;
first_name: text;
last_name: text;
email: text;
verification_token: text;
verified: bool;
submitted_at: nat64;
verified_at: opt nat64;
ip_hash: opt text;
ii_principal: opt principal;
auth_methods: vec AuthMethod;
preferred_auth_method: opt AuthMethodType;
};AuthMethod
Authentication method record:
type AuthMethod = record {
method_type: AuthMethodType;
identifier: text;
credential: opt Credential;
verified: bool;
linked_at: nat64;
last_used: opt nat64;
};
type Credential = variant {
PasswordHash: blob;
OidcToken: OidcTokenData;
Principal: principal;
};CreateAccountRequest
Account creation payload:
type CreateAccountRequest = record {
first_name: text;
last_name: text;
email: text;
password: text;
encrypted_recovery_key: blob; // AES-256-GCM encrypted
password_salt: blob; // PBKDF2 salt
};Methods
Account Creation
create_account
Create a new user account with email/password.
"create_account": (CreateAccountRequest) -> (CreateAccountResponse);TypeScript Example:
// Client-side: Generate recovery key and encrypt
const recoveryKey = crypto.getRandomValues(new Uint8Array(32));
const salt = crypto.getRandomValues(new Uint8Array(16));
const passwordKey = await deriveKeyFromPassword(password, salt);
const encryptedRecoveryKey = await encrypt(recoveryKey, passwordKey);
const result = await userActor.create_account({
first_name: 'John',
last_name: 'Doe',
email: 'john@example.com',
password: 'securePassword123',
encrypted_recovery_key: encryptedRecoveryKey,
password_salt: salt,
});submit_individual
Submit individual registration (legacy/interest form).
"submit_individual": (IndividualRequest, opt AddressRequest) -> (IndividualResult);Email Verification
verify_email
Verify email with token from email link.
"verify_email": (token: text) -> (VerifyResult);verify_code
Verify email with 6-digit code.
"verify_code": (email: text, code: text, first_name: text, last_name: text) -> (VerifyResult);resend_verification_code
Request new verification code.
"resend_verification_code": (email: text) -> (VerifyResult);Authentication
authenticate_with_password
Login with email/password.
"authenticate_with_password": (
AuthRequest,
device_fingerprint: text,
ip_address: opt text,
timezone: opt text,
user_agent: opt text
) -> (AuthResponse);authenticate_with_internet_identity
Login with Internet Identity.
"authenticate_with_internet_identity": (
device_fingerprint: text,
ip_address: opt text,
timezone: opt text,
user_agent: opt text
) -> (AuthResponse);Uses ic_cdk::caller() to get II principal automatically.
Password Management
set_password
Set or change password.
"set_password": (user_id: text, SetPasswordRequest) -> (variant { Ok; Err: text });
type SetPasswordRequest = record {
current_password: opt text;
new_password: text;
encrypted_recovery_key: opt blob;
password_salt: opt blob;
};initiate_password_reset
Start password reset flow.
"initiate_password_reset": (email: text) -> (variant { Ok: text; Err: text });complete_password_reset
Complete password reset.
"complete_password_reset": (
email: text,
reset_code: text,
new_password: text,
encrypted_recovery_key_base64: text,
password_salt_base64: text
) -> (variant { Ok: text; Err: text });Internet Identity Linking
link_ii_principal
Link II to existing account.
"link_ii_principal": (user_id: text, ii_principal: principal) -> (variant { Ok; Err: text });unlink_ii_principal
Remove II link from account.
"unlink_ii_principal": (user_id: text) -> (variant { Ok; Err: text });get_user_by_ii_principal (query)
Find user by II principal.
"get_user_by_ii_principal": (principal) -> (variant { Ok: text; Err: text }) query;Self-Custody Verification
check_self_custody_status (query)
Check wallet verification status.
"check_self_custody_status": (user_id: text) -> (variant { Ok: SelfCustodyStatus; Err: text }) query;
type SelfCustodyStatus = variant {
Verified;
Expired;
NeverVerified;
};Address Management
add_address
Add address to user profile.
"add_address": (individual_id: text, AddressRequest) -> (variant { Ok: text; Err: text });get_addresses_for_individual (query)
Get all addresses for user.
"get_addresses_for_individual": (individual_id: text) -> (vec Address) query;GDPR Compliance
request_kyc_data_deletion
Request deletion of KYC data (30-day grace period).
"request_kyc_data_deletion": () -> (variant { Ok; Err: text });cancel_kyc_data_deletion
Cancel pending deletion request.
"cancel_kyc_data_deletion": () -> (variant { Ok; Err: text });Duplicate Prevention
check_duplicate_id_hash
Check if ID hash already exists (for KYC).
"check_duplicate_id_hash": (id_type: text, country: text, id_number: text) -> (variant { Ok: bool; Err: text });Membership Integration
check_and_mint_membership
Mint membership NFT for verified user.
"check_and_mint_membership": (user_id: text) -> (variant { Ok: nat64; Err: text });Returns ICRC-7 token ID on success.
Statistics
get_stats (query)
Get user statistics.
"get_stats": () -> (Stats) query;
type Stats = record {
total_individuals: nat64;
verified_individuals: nat64;
pending_verifications: nat64;
};Error Messages
| Error | Cause | Resolution |
|---|---|---|
Email already registered | Duplicate email | Use password reset |
Invalid verification code | Wrong/expired code | Request new code |
Password too weak | Doesn't meet requirements | Use stronger password |
User not found | Invalid user ID | Check user exists |
Duplicate ID detected | KYC ID already registered | Contact support |