Profile API
Sigma Auth provides profile management endpoints for creating and retrieving user profiles associated with Bitcoin identities.
Overview
User profiles in Sigma Auth are:
- Stored in the auth server's KV storage (not on blockchain)
- Associated with BAP (Bitcoin Attestation Protocol) identities
- Included in JWT tokens and available via the
/userinfo
endpoint - Following Schema.org Person structure for future extensibility
Profile Structure
interface UserProfile {
bapId: string; // BAP identity key
address: string; // Bitcoin address derived from BAP
identity: { // Schema.org Person-compatible fields
alternateName?: string; // Username/handle
image?: string; // Avatar URL
description?: string; // Bio/description
};
isPublished: boolean; // Whether published on-chain (future feature)
createdAt: number; // Unix timestamp
updatedAt: number; // Unix timestamp
block?: number; // Block height when published (future feature)
}
Endpoints
Get User Profile
GET /api/profile
Retrieves the profile for the authenticated user.
Headers:
Authorization: Bearer <access_token>
Response (200 OK):
{
"success": true,
"profile": {
"bapId": "GpWrvdYWq3DUWMcw8vF8cFYoBK7",
"address": "1ProfileAddressExample...",
"identity": {
"alternateName": "johndoe",
"image": "https://example.com/avatar.jpg",
"description": "Bitcoin developer and enthusiast"
},
"isPublished": false,
"createdAt": 1705123456789,
"updatedAt": 1705123456789
}
}
Response (404 Not Found):
{
"success": false,
"error": "profile_not_found",
"message": "No profile exists for this user"
}
Create User Profile
POST /api/profile/create
Creates a new BAP identity and profile for the authenticated user.
Headers:
Authorization: Bearer <access_token>
Content-Type: application/json
Request Body:
{
"alternateName": "johndoe", // Optional: username/handle
"image": "https://example.com/avatar.jpg", // Optional: avatar URL
"description": "Bitcoin developer", // Optional: bio
"password": "backup-password" // REQUIRED: Password to decrypt user's backup
}
Important: The password is used ONLY to decrypt the user's encrypted backup containing their BAP keys. It is never stored.
Response (200 OK):
{
"success": true,
"profile": {
"idKey": "GpWrvdYWq3DUWMcw8vF8cFYoBK7",
"address": "1ProfileAddressExample...",
"profileData": {
"alternateName": "johndoe",
"image": "https://example.com/avatar.jpg",
"description": "Bitcoin developer"
}
},
"message": "Profile created successfully. Please re-authenticate to get updated token."
}
Response (400 Bad Request):
{
"error": "no_backup_found",
"message": "Please create a backup first using /backup endpoint"
}
Response (401 Unauthorized):
{
"error": "invalid_password"
}
Response (409 Conflict):
{
"error": "profile_already_exists"
}
Update User Profile
PUT /api/profile
Updates the authenticated user's profile data.
Headers:
Authorization: Bearer <access_token>
Content-Type: application/json
Request Body:
{
"alternateName": "newusername", // Optional
"image": "https://example.com/new-avatar.jpg", // Optional
"description": "Updated bio" // Optional
}
Response (200 OK):
{
"success": true,
"profile": {
"bapId": "GpWrvdYWq3DUWMcw8vF8cFYoBK7",
"address": "1ProfileAddressExample...",
"identity": {
"alternateName": "newusername",
"image": "https://example.com/new-avatar.jpg",
"description": "Updated bio"
},
"isPublished": false,
"createdAt": 1705123456789,
"updatedAt": 1705127856789
}
}
Profile in UserInfo Endpoint
Once a profile is created, it's automatically included in the /userinfo
endpoint response:
GET /userinfo
Response with profile:
{
"pubkey": "02a94e09bcd6085e580f9214d2814e985f348b1b24121b2aff70a169f971ff5699",
"bapIdKey": "GpWrvdYWq3DUWMcw8vF8cFYoBK7",
"profile": {
"bapId": "GpWrvdYWq3DUWMcw8vF8cFYoBK7",
"address": "1ProfileAddressExample...",
"identity": {
"alternateName": "johndoe",
"image": "https://example.com/avatar.jpg",
"description": "Bitcoin developer and enthusiast"
},
"isPublished": false,
"createdAt": 1705123456789,
"updatedAt": 1705123456789
}
}
Response without profile:
{
"pubkey": "02a94e09bcd6085e580f9214d2814e985f348b1b24121b2aff70a169f971ff5699"
}
Integration Guide
1. Check if User Has Profile
const response = await fetch('https://auth.sigmaidentity.com/userinfo', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const userInfo = await response.json();
if (userInfo.profile) {
// User has a profile
console.log('Username:', userInfo.profile.identity.alternateName);
} else {
// User needs to create a profile
showCreateProfileUI();
}
2. Create Profile
// Note: User must have a backup first
const createProfile = async (profileData: {
alternateName?: string;
image?: string;
description?: string;
password: string; // Required to decrypt backup
}) => {
const response = await fetch('https://auth.sigmaidentity.com/api/profile/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(profileData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || error.error);
}
const result = await response.json();
// Important: User needs to re-authenticate to get updated JWT with profile
window.location.href = '/api/auth/signin';
};
3. Update Profile
const updateProfile = async (updates: {
alternateName?: string;
image?: string;
description?: string;
}) => {
const response = await fetch('https://auth.sigmaidentity.com/api/profile', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || error.error);
}
return await response.json();
};
Important Notes
Profile Creation Requirements
- Backup Required: User must have created an encrypted backup first
- Password Required: The backup password is needed to decrypt BAP keys
- One Profile Per User: Each Bitcoin identity can have one profile
- Re-authentication: After creating a profile, users should re-authenticate to get an updated JWT token containing their profile
Profile Data Storage
- Profiles are stored in Cloudflare KV storage, not on the blockchain
- The
isPublished
field is for future blockchain publishing functionality - Profile data is included directly in JWT tokens for performance
Schema.org Compatibility
The identity
object follows Schema.org Person structure, allowing future expansion with fields like:
name
(full name)email
url
(website)location
jobTitle
- And other Schema.org Person properties
Error Handling
Always handle profile endpoint errors gracefully:
async function getUserProfile(accessToken: string) {
try {
const response = await fetch('https://auth.sigmaidentity.com/userinfo', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const userInfo = await response.json();
// Profile may not exist - handle gracefully
return userInfo.profile || null;
} catch (error) {
console.error('Failed to fetch profile:', error);
return null;
}
}
Next Steps
- Review the Authentication Guide for auth flow details
- See Backup API for backup creation
- Check API Overview for other endpoints