
Identity
- 13 installs
- 610 repo stars
- Updated June 26, 2026
- alsk1992/cloddsbot
identity is a Claude Code skill that manages user identity, OAuth connections, sessions and device authentication for an app.
About
identity is a Claude Code skill that manages user identity, OAuth provider connections and device authentication. It links Google, GitHub, Discord and Twitter accounts, lists and revokes devices and sessions, and assigns owner, paired or stranger trust levels. A developer uses it to add auth, session and device management to a bot backed by a SQLite store.
- Manages user identity, OAuth provider links and device authentication
- Handles sessions, device revocation and owner/paired/stranger trust levels
- Ships a TypeScript service with SQLite storage and OAuth callback handling
Identity by the numbers
- 13 all-time installs (skills.sh)
- Ranked #1,634 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
identity capabilities & compatibility
Free skill; requires OAuth client credentials for each provider.
- Capabilities
- oauth login · session management · device management · identity management
- Works with
- github · gmail
- Use cases
- security audit
- Pricing
- Bring your own API key
What identity says it does
Manage user identity, OAuth provider connections, and device authentication.
Backup auth methods
npx skills add https://github.com/alsk1992/cloddsbot --skill identityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 610 |
| Last updated | June 26, 2026 |
| Repository | alsk1992/cloddsbot ↗ |
What it does
Add user identity, OAuth provider linking, session and device management to a bot with owner/paired/stranger trust levels.
Who is it for?
Adding OAuth auth, session and device management with trust levels to an app or bot.
When should I use this skill?
You need to link OAuth providers, manage sessions/devices or set user trust levels.
What you get
A working identity layer with OAuth links, device and session management and trust levels.
- OAuth provider linking
- session and device management
- trust-level assignment
By the numbers
- 4 OAuth providers (Google, GitHub, Discord, Twitter)
- 3 trust levels (owner, paired, stranger)
- 4 device types (desktop, mobile, tablet, unknown)
Files
Identity - Complete API Reference
Manage user identity, OAuth provider connections, and device authentication.
---
Chat Commands
View Identity
/identity Show your identity
/identity status Auth status
/identity devices List linked devicesOAuth Providers
/identity providers List available providers
/identity link google Connect Google account
/identity link github Connect GitHub account
/identity unlink google Disconnect providerDevice Management
/identity device list List devices
/identity device name "Work Laptop" Name this device
/identity device revoke <id> Revoke device access
/identity device revoke-all Revoke all except currentTrust & Security
/identity trust View trust level
/identity sessions Active sessions
/identity session logout <id> End session
/identity security Security settings---
TypeScript API Reference
Create Identity Service
import { createIdentityService } from 'clodds/identity';
const identity = createIdentityService({
// OAuth providers
providers: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
},
// Session settings
sessionDurationMs: 86400000 * 30, // 30 days
deviceTrustDurationMs: 86400000 * 90, // 90 days
// Storage
storage: 'sqlite',
dbPath: './identity.db',
});Get User Identity
const user = await identity.getUser(userId);
console.log(`ID: ${user.id}`);
console.log(`Name: ${user.displayName}`);
console.log(`Email: ${user.email}`);
console.log(`Trust level: ${user.trustLevel}`);
console.log(`Created: ${user.createdAt}`);Link OAuth Provider
// Generate OAuth URL
const authUrl = identity.getOAuthUrl('google', {
redirectUri: 'https://your-domain.com/auth/callback',
state: 'random-state-string',
scopes: ['email', 'profile'],
});
// Handle callback
const result = await identity.handleOAuthCallback('google', {
code: 'oauth-code-from-callback',
state: 'random-state-string',
});
console.log(`Linked: ${result.provider}`);
console.log(`Email: ${result.email}`);List Linked Providers
const providers = await identity.getLinkedProviders(userId);
for (const provider of providers) {
console.log(`${provider.name}: ${provider.email}`);
console.log(` Linked: ${provider.linkedAt}`);
console.log(` Last used: ${provider.lastUsed}`);
}Unlink Provider
await identity.unlinkProvider(userId, 'google');Device Management
// List devices
const devices = await identity.getDevices(userId);
for (const device of devices) {
console.log(`${device.id}: ${device.name || 'Unknown'}`);
console.log(` Type: ${device.type}`); // 'desktop' | 'mobile' | 'tablet'
console.log(` Browser: ${device.browser}`);
console.log(` OS: ${device.os}`);
console.log(` Last seen: ${device.lastSeen}`);
console.log(` Current: ${device.isCurrent}`);
}
// Name device
await identity.nameDevice(userId, deviceId, 'Work Laptop');
// Revoke device
await identity.revokeDevice(userId, deviceId);
// Revoke all except current
await identity.revokeAllDevices(userId, { exceptCurrent: true });Session Management
// List active sessions
const sessions = await identity.getSessions(userId);
for (const session of sessions) {
console.log(`${session.id}: ${session.device}`);
console.log(` Started: ${session.startedAt}`);
console.log(` Last active: ${session.lastActive}`);
console.log(` IP: ${session.ip}`);
}
// End session
await identity.endSession(sessionId);
// End all sessions
await identity.endAllSessions(userId);Trust Level
// Get trust level
const trust = await identity.getTrustLevel(userId);
console.log(`Trust: ${trust}`); // 'owner' | 'paired' | 'stranger'
// Set trust level (admin only)
await identity.setTrustLevel(userId, 'paired');---
Trust Levels
| Level | Access |
|---|---|
| owner | Full admin access |
| paired | Standard user access |
| stranger | No access (must pair) |
---
OAuth Providers
| Provider | Scopes |
|---|---|
| email, profile | |
| GitHub | user:email |
| Discord | identify, email |
| users.read |
---
Device Types
| Type | Detection |
|---|---|
desktop | Windows, macOS, Linux |
mobile | iOS, Android |
tablet | iPad, Android tablet |
unknown | Unrecognized UA |
---
Best Practices
1. Link multiple providers — Backup auth methods 2. Review devices regularly — Revoke unused ones 3. Name your devices — Easier to identify 4. Check sessions — Monitor for suspicious access 5. Use strong auth — OAuth over passwords
/**
* Identity CLI Skill
*
* Commands:
* /identity lookup <agent-id|address> - Look up an agent identity
* /identity register <token-uri> - Register a new agent identity
* /identity verify <agent-id|address> - Full verification with reputation
* /identity stats - Registry statistics
*/
async function execute(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
const cmd = parts[0]?.toLowerCase() || 'help';
try {
const identityMod = await import('../../../identity/index');
const network = (process.env.ERC8004_NETWORK as any) || 'base';
switch (cmd) {
case 'lookup':
case 'get': {
if (parts.length < 2) return 'Usage: /identity lookup <agent-id | 0xAddress>';
const input = parts[1];
const client = identityMod.createERC8004Client(network);
// Determine if input is a numeric agent ID or an address
if (/^\d+$/.test(input)) {
const agentId = parseInt(input, 10);
const agent = await client.getAgent(agentId);
if (!agent) return `Agent ID ${agentId} not found on ${network}.`;
let output = `**Agent #${agent.agentId}**\n\n`;
output += `Owner: \`${agent.owner}\`\n`;
output += `Network: ${agent.network} (chain ${agent.chainId})\n`;
output += `Token URI: ${agent.tokenURI}\n`;
if (agent.card) {
output += `\n**Agent Card:**\n`;
output += ` Name: ${agent.card.name}\n`;
if (agent.card.description) output += ` Description: ${agent.card.description}\n`;
if (agent.card.endpoints?.length) {
output += ` Endpoints:\n`;
for (const ep of agent.card.endpoints) {
output += ` - ${ep.name}: ${ep.endpoint}\n`;
}
}
}
return output;
} else {
// Address lookup
const agent = await client.getAgentByOwner(input);
if (!agent) return `No agent identity found for address \`${input}\` on ${network}.`;
let output = `**Agent #${agent.agentId}** (owned by \`${input}\`)\n\n`;
output += `Network: ${agent.network} (chain ${agent.chainId})\n`;
output += `Token URI: ${agent.tokenURI}\n`;
if (agent.card) {
output += `Name: ${agent.card.name}\n`;
if (agent.card.description) output += `Description: ${agent.card.description}\n`;
}
return output;
}
}
case 'register':
case 'reg': {
if (parts.length < 2) return 'Usage: /identity register <token-uri>\n\nRequires ERC8004_PRIVATE_KEY env var.';
const tokenURI = parts[1];
const privateKey = process.env.ERC8004_PRIVATE_KEY;
if (!privateKey) {
return 'Registration requires ERC8004_PRIVATE_KEY environment variable to be set.';
}
const client = identityMod.createERC8004Client(network, privateKey);
const result = await client.register(tokenURI);
let output = `**Agent Registered**\n\n`;
output += `Agent ID: ${result.agentId}\n`;
output += `Transaction: \`${result.txHash}\`\n`;
output += `Network: ${network}\n`;
output += `Formatted ID: ${identityMod.formatAgentId(result.agentId)}\n`;
return output;
}
case 'verify':
case 'check': {
if (parts.length < 2) return 'Usage: /identity verify <agent-id | 0xAddress>';
const input = parts[1];
// Use the convenience function or full client
let result;
if (/^\d+$/.test(input)) {
result = await identityMod.verifyAgent(parseInt(input, 10), network);
} else {
const client = identityMod.createERC8004Client(network);
result = await client.verify(input);
}
let output = `**Verification Result**\n\n`;
output += `Verified: ${result.verified ? 'Yes' : 'No'}\n`;
if (result.agentId != null) output += `Agent ID: ${result.agentId}\n`;
if (result.owner) output += `Owner: \`${result.owner}\`\n`;
if (result.name) output += `Name: ${result.name}\n`;
if (result.error) output += `Note: ${result.error}\n`;
if (result.reputation) {
output += `\n**Reputation:**\n`;
output += ` Feedback count: ${result.reputation.feedbackCount}\n`;
output += ` Average score: ${result.reputation.averageScore}/100\n`;
}
return output;
}
case 'has':
case 'exists': {
if (parts.length < 2) return 'Usage: /identity has <0xAddress>';
const address = parts[1];
const has = await identityMod.hasIdentity(address, network);
return has
? `Address \`${address}\` **has** a registered agent identity on ${network}.`
: `Address \`${address}\` does **not** have a registered agent identity on ${network}.`;
}
case 'reputation':
case 'rep': {
if (parts.length < 2) return 'Usage: /identity reputation <agent-id>';
const agentId = parseInt(parts[1], 10);
if (isNaN(agentId)) return 'Agent ID must be a number.';
const client = identityMod.createERC8004Client(network);
const rep = await client.getReputation(agentId);
if (!rep) return `No reputation data for agent #${agentId}.`;
let output = `**Reputation for Agent #${agentId}**\n\n`;
output += `Feedback count: ${rep.feedbackCount}\n`;
output += `Average score: ${rep.averageScore}/100\n`;
return output;
}
case 'stats':
case 'total': {
const client = identityMod.createERC8004Client(network);
const total = await client.getTotalAgents();
return `**ERC-8004 Registry Stats** (${network})\n\nTotal registered agents: ${total}\nContract: \`${identityMod.ERC8004_CONTRACTS.identity}\``;
}
case 'format': {
if (parts.length < 2) return 'Usage: /identity format <agent-id>';
const agentId = parseInt(parts[1], 10);
if (isNaN(agentId)) return 'Agent ID must be a number.';
return `Formatted: \`${identityMod.formatAgentId(agentId)}\``;
}
case 'parse': {
if (parts.length < 2) return 'Usage: /identity parse <eip155:chainId:registry:agentId>';
const parsed = identityMod.parseAgentId(parts[1]);
if (!parsed) return `Could not parse "${parts[1]}". Expected format: eip155:<chainId>:<registry>:<agentId>`;
return `**Parsed Agent ID**\n\nChain ID: ${parsed.chainId}\nRegistry: \`${parsed.registry}\`\nAgent ID: ${parsed.agentId}`;
}
default:
return helpText();
}
} catch (error) {
return `Error: ${error instanceof Error ? error.message : String(error)}`;
}
}
function helpText(): string {
return `**Identity Commands** (ERC-8004)
/identity lookup <id|address> - Look up agent identity
/identity register <token-uri> - Register new agent (needs key)
/identity verify <id|address> - Full verification + reputation
/identity has <address> - Check if address has identity
/identity reputation <id> - Get reputation score
/identity stats - Registry statistics
/identity format <id> - Format agent ID (EIP-155)
/identity parse <formatted> - Parse formatted agent ID
Set ERC8004_NETWORK env var (default: base). Set ERC8004_PRIVATE_KEY for registration.`;
}
export default {
name: 'identity',
description: 'ERC-8004 agent identity lookup, registration, and verification',
commands: ['/identity', '/id'],
handle: execute,
};