Identity System & User Profiles

Cloudillo Profiles are located using a DNS-based identity system. Each Cloudillo Identity is associated with a specific API endpoint, which can be accessed via the “cl-o” subdomain of the identity. For example, the API domain of the cloudillo.net identity is available at https://cl-o.cloudillo.net/.

Retrieving a Cloudillo Profile

You can retrieve a Cloudillo profile by making an API request to the /api/me endpoint of the identity’s API domain:

curl https://cl-o.cloudillo.net/api/me

Example response:

{
  "idTag": "cloudillo.net",
  "name": "Cloudillo",
  "type": "community",
  "profilePic": "QoEYeG8TJZ2HTGhVlrtTDBpvBGOp6gfGhq4QmD6Z46w",
  "keys": [
    {
      "keyId": "20250205",
      "publicKey": "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENSq6EZZ+xCypWNkm+0+MHIZfLX7I01wTT+SOw7DoOUOuDAWKMkhBVG+SUb9AzCxEOlmkefuEW5zmXNwmH2MphEQW/r18RDjd+Nt5nbemBsoQzsm2Wg/mUyWBsKYs1oe5"
    }
  ]
}

Profile Fields Explained

  • idTag: The Identity Tag associated with the profile.
  • name: The display name of the profile.
  • type: Either empty for a personal profile or contains “community” for community profiles.
  • profilePic: The identifier for the profile picture, which can be retrieved via the storage API.
  • keys: A list of cryptographic keys associated with the profile.

Profile Picture Retrieval

The profilePic field contains an identifier that allows retrieval of the profile’s profile picture using the Cloudillo Storage API. A request to retrieve the profile picture may look like this:

curl https://cl-o.nikita.cloudillo.net/api/store/NMzE4gNI29aEkiV6Q7I1UNWh4x2gFZ7753Pl74veYtU

Key Management

A profile supports multiple cryptographic keys, enabling periodic key rotation for enhanced security. Older keys can be deprecated while maintaining account integrity.

Key Structure

Each profile key contains:

pub struct ProfileKey {
    key_id: String,        // Identifier (e.g., "20250205")
    public_key: String,    // Base64-encoded P384 public key
    created_at: i64,       // Unix timestamp
    expires_at: Option<i64>,  // Optional expiration
    key_type: KeyType,     // Purpose of the key
}

pub enum KeyType {
    Signing,    // For action token signatures
    VAPID,      // For push notifications
    // Future: Encryption, Authentication, etc.
}

Cryptographic Algorithms

Cloudillo uses elliptic curve cryptography for signing:

  • Curve: P384 (NIST P-384, also known as secp384r1)
  • Algorithm: ES384 (ECDSA using P-384 and SHA-384)
  • Key Size: 384 bits
  • Signature Size: ~96 bytes

Key Rotation

Keys are rotated by generating a new key (keyId = current date), adding it to the profile alongside existing keys, and marking old keys as expired after a 30-90 day grace period.

VAPID Keys

VAPID (Voluntary Application Server Identification) keys are used for web push notifications:

pub struct VapidKey {
    key_id: String,
    public_key: String,   // Base64-encoded
    private_key: String,  // Stored in AuthAdapter, never exposed
    contact: String,      // mailto: or https: URI
}

These are separate from signing keys to isolate concerns and enable different rotation policies.

Identity Resolution

DNS-Based Discovery

Cloudillo uses DNS to discover the API endpoint for an identity:

  1. Identity: alice.example.com
  2. API Domain: cl-o.alice.example.com
  3. API Endpoint: https://cl-o.alice.example.com/api/me

Cloudillo Identity Providers (CIP)

Users without their own domain can use a Cloudillo Identity Provider:

CIP Responsibilities:

  • Domain management (subdomains or custom domains)
  • DNS configuration
  • Dynamic DNS support
  • CIPs never store or access any user data, nor have any rescponsibilities about it.

Example CIP: cloudillo.net

  • Provides identities like alice.cloudillo.net
  • API available at https://cl-o.alice.cloudillo.net
  • Users can migrate to their own domain later

Custom Domain Setup

To use your own domain with Cloudillo:

  1. DNS Configuration:
cl-o.alice.example.com.  A      <your-server-ip>
cl-o.alice.example.com.  AAAA   <your-server-ipv6>
app.example.com.  A             <your-server-ip>
app.example.com.  AAAA          <your-server-ipv6>
  1. TLS Certificate: Automatic via ACME (Let’s Encrypt)
ACME_EMAIL=admin@example.com
  1. Bootstrap: Configure tenant
BASE_ID_TAG=alice.example.com
BASE_APP_DOMAIN=app.example.com
BASE_PASSWORD=<secure-password>

Profile Metadata

Storage

Profile metadata is stored in the MetaAdapter:

pub struct ProfileMetadata {
    tn_id: TnId,           // Internal tenant ID
    id_tag: String,        // Public identifier
    name: String,          // Display name
    profile_type: ProfileType,
    profile_pic: Option<String>,  // File ID
    bio: Option<String>,
    created_at: i64,
    updated_at: i64,
}

pub enum ProfileType {
    Personal,
    Community,
}

Synchronization

Profiles can be synchronized across instances for caching:

GET https://cl-o.{remote_id_tag}/api/me
Parse JSON response
Cache locally in MetaAdapter

Security Considerations

Public Key Infrastructure

  • Public keys are publicly accessible via /api/me
  • Private keys are stored securely in AuthAdapter
  • No private key export - keys never leave the server
  • Key verification happens on every action token

Identity Trust Model

Trust is established through:

  1. DNS ownership: Control of domain proves identity ownership
  2. Key signatures: Private key proves control of identity
  3. HTTPS: TLS proves server authenticity
  4. Action signatures: ES384 signatures prove action authenticity

Attack Mitigation

DNS Hijacking:

  • Old signatures remain valid (past actions can’t be forged)
  • Users can verify key changes

Key Compromise:

  • Rotate immediately to new key
  • Mark compromised key as expired
  • Past actions become invalid

Server Compromise:

  • Private keys in AuthAdapter may need HSM/vault for high-security deployments
  • Separate AuthAdapter storage from other adapters
  • Regular security audits

API Reference

GET /api/me

Retrieve public profile information.

Request:

curl https://cl-o.example.com/api/me

Response (200 OK):

{
  "idTag": "example.com",
  "name": "Alice",
  "type": "",
  "profilePic": "f1~Qo...46w",
  "keys": [
    {
      "keyId": "20250205",
      "publicKey": "MHYwEAYHKoZIzj0CAQ..."
    }
  ]
}

GET /api/me/keys

Returns all public keys with createdAt, expiresAt, and keyType fields (for action token verification).

See Also