Trust Score

Every Passji identity builds a trust score over time. Use it for progressive access control and risk-based decisions.

What is Trust Scoring?

Trust scores are a number between 0.0 and 1.0 that represent the reputation of an identity. Unlike traditional verification (email, phone, ID), trust scores are earned over time through consistent, legitimate usage.

New accounts start with low trust. As users authenticate regularly, use multiple apps, and maintain good security hygiene, their trust score increases.

Why trust scoring? Traditional identity systems are binary - you're verified or you're not. Trust scores provide a spectrum that apps can use for nuanced access control. A brand-new account can still use your app, just with fewer privileges until they build trust.

Trust Signals

Trust scores are computed from five weighted signals:

Account Age

30%

How long the identity has existed. Ramps linearly over 180 days.

Max contribution: 180 days

Auth Frequency

20%

Regular usage indicates a real, active identity. Logarithmic scale.

Max contribution: 100 auths

App Diversity

25%

Using multiple apps shows real-world utility. Caps at 10 unique apps.

Max contribution: 10 apps

Multi-Device

10%

Passkeys registered on multiple devices indicate good security hygiene.

Max contribution: 5 devices

Activity Recency

15%

Recent activity bonus that decays over 30 days of inactivity.

Max contribution: Active in last 30 days

Score Calculation

The trust score is a weighted sum of normalized signals:

Formula
trust_score =
    0.30 * min(account_age_days / 180, 1.0)
  + 0.20 * min(log10(auth_count + 1) / 2, 1.0)
  + 0.25 * min(unique_apps / 10, 1.0)
  + 0.10 * min(device_count / 5, 1.0)
  + 0.15 * max(1.0 - days_since_last_auth / 30, 0.0)

// Result is clamped to [0.0, 1.0]

Score Examples

ScenarioScoreNotes
Brand new account~0.15Clean history only
30 days, 10 auths, 2 apps~0.40Casual user
90 days, 50 auths, 5 apps, 2 devices~0.65Active user
180+ days, 100+ auths, 10+ apps, 3+ devices~0.95Power user

Requesting Trust Data

To receive trust information in tokens, include the trust scope in your authorization request:

Authorization Request
// Request trust information in your auth flow
const authUrl = new URL("https://passji.com/authorize");
authUrl.searchParams.set("client_id", "your_client_id");
authUrl.searchParams.set("redirect_uri", "https://yourapp.com/callback");
authUrl.searchParams.set("response_type", "code");
authUrl.searchParams.set("scope", "openid emoji trust"); // Include 'trust'
authUrl.searchParams.set("state", generateState());

// The id_token will include trust_score and account_age_days

Token Response

ID Token with Trust
// ID token with trust scope
{
  "iss": "https://passji.com",
  "sub": "usr_abc123",
  "emoji_id": "🦊🌸🎯",
  "trust_score": 0.85,           // 0.0 to 1.0
  "account_age_days": 45,        // Days since registration
  "auth_method": "webauthn"
}

Progressive Access Control

Use trust scores to implement progressive access - grant more privileges as users build trust:

Progressive Access
// Progressive access based on trust score
function checkAccess(user, action) {
  const trustScore = user.trust_score;

  switch (action) {
    case "read_public":
      return true; // Anyone can read

    case "post_content":
      if (trustScore < 0.3) {
        return { allowed: false, reason: "Account too new" };
      }
      return { allowed: true };

    case "send_messages":
      if (trustScore < 0.5) {
        return { allowed: false, reason: "Build more trust first" };
      }
      return { allowed: true };

    case "withdraw_funds":
      if (trustScore < 0.8) {
        return { allowed: false, reason: "High trust required" };
      }
      return { allowed: true };

    default:
      return { allowed: false };
  }
}

Example Thresholds

Trust LevelRangeSuggested Access
Minimal0.0 - 0.3Read-only, limited API calls, no messaging
Basic0.3 - 0.5Create content, basic interactions
Standard0.5 - 0.7Full features, messaging, transactions
Elevated0.7 - 0.9Moderator roles, higher limits
Maximum0.9 - 1.0Admin features, sensitive operations

UI Patterns

You can show users their trust level to encourage engagement and explain access restrictions:

Trust Badge Component
// Display trust tier to users
function TrustBadge({ trustScore }) {
  const tier = getTrustTier(trustScore);

  return (
    <div className="flex items-center gap-2">
      <span className="text-2xl">{tier.emoji}</span>
      <div>
        <div className="font-medium">{tier.name}</div>
        <div className="text-sm text-muted-foreground">
          {tier.description}
        </div>
      </div>
    </div>
  );
}

function getTrustTier(score) {
  if (score >= 0.9) return {
    emoji: "🌟",
    name: "Stellar",
    description: "Maximum trust - long history, diverse usage"
  };
  if (score >= 0.7) return {
    emoji: "✨",
    name: "Established",
    description: "Well-established identity"
  };
  if (score >= 0.5) return {
    emoji: "🌱",
    name: "Growing",
    description: "Building trust over time"
  };
  if (score >= 0.3) return {
    emoji: "🌿",
    name: "Newcomer",
    description: "New but active account"
  };
  return {
    emoji: "🌰",
    name: "Fresh",
    description: "Just getting started"
  };
}

Best Practices

  • Don't block completely - Even low-trust users should be able to use basic features. This builds trust over time.
  • Explain restrictions - Tell users why they can't access something and how to build trust.
  • Use appropriate thresholds - High-risk actions need high trust. Read-only operations can be open to anyone.
  • Combine with other signals - Trust scores work best alongside other context (rate limiting, content moderation).
  • Cache appropriately - Trust scores don't change frequently. Refresh on login, not every request.

Remember: Trust scores are probabilistic, not deterministic. A high trust score doesn't guarantee good behavior, and a low score doesn't mean bad intent. Use them as one signal among many.