> ## Documentation Index
> Fetch the complete documentation index at: https://docs.armature.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Identifying users

> Attribute sessions to the right user or account

Armature attributes every tool call to an **actor** — a stable, privacy-preserving identifier for the user or account behind the session.

## The default

Out of the box, the SDK derives an actor seed from the request's authentication, in order:

1. A configured `actorId` (if you set one — see below)
2. The request's auth info: token, client ID, API key, or principal ID
3. The `Authorization` header
4. `"anonymous"` as the last resort

The seed is **SHA-256 hashed before transmission** — raw tokens and header values never leave your server. Two sessions from the same authenticated user hash to the same actor, so per-user views line up without Armature ever seeing the credential.

## Custom actor resolution

If your server knows the real user (for example, after validating an OAuth token), resolve the actor yourself so sessions group by *your* user IDs:

<CodeGroup>
  ```typescript TypeScript theme={null}
  createMcpAnalyticsServer(buildServer, {
    armature: {
      actorId: (context) => context?.authInfo?.principalId ?? "anonymous",
    },
  });
  ```

  ```python Python theme={null}
  instrument_fastmcp(mcp, {
      "armature": {
          # sync or async callable, or a plain string
          "actor_id": lambda context: resolve_user_id(context),
      }
  })
  ```

  ```go Go theme={null}
  config := armatureanalytics.EnvConfig()
  config.ActorSeed = func(ctx context.Context) string {
  	if user, ok := auth.UserFromContext(ctx); ok {
  		return user.ID
  	}
  	return ""
  }
  ```
</CodeGroup>

Whatever you return is still hashed before it is sent.

<Warning>
  In the Go official-SDK adapter, install the analytics middleware **before** your auth middleware if `ActorSeed` reads values that auth injects into the context — otherwise the actor resolves before auth has run.
</Warning>

## Anonymous traffic

Unauthenticated servers still get useful sessions: the actor falls back to `anonymous`, and session identity (which conversation the calls belong to) is tracked separately via the MCP session ID. You lose per-user grouping, not session replay.
