Skip to content

openkitx403/openkitx403

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

46 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

OpenKitx403

HTTP-native wallet authentication protocol for Solana.

OpenKitx403 is an open-source, TypeScript-first protocol that standardizes HTTP 403 as the semantic "prove you control this wallet" challenge for Solana wallet authentication.

npm client npm server PyPI server PyPI client License: MIT

HTTP-native wallet authentication for Solana

Features

  • HTTP-native: Uses standard HTTP 403 challenges
  • Stateless: No server-side sessions required
  • Secure: Ed25519 signature verification with replay protection
  • Easy to use: Drop-in middleware for Express, Fastify, and FastAPI
  • Production-ready: Full TypeScript and Python SDKs
  • AI-friendly: LangChain integration and agent support
  • Token-gating ready: Built-in support for NFT/token requirements

πŸ“¦ Installation

TypeScript Client (Browser/Node)

npm install @openkitx403/client

TypeScript Server (Express/Fastify)

npm install @openkitx403/server

Python Server (FastAPI)

pip install openkitx403

or
poetry add openkitx403

πŸš€ Quick Start

Browser Client

import { OpenKit403Client } from '@openkitx403/client';

const client = new OpenKit403Client();

// Connect wallet
await client.connect('phantom');

// Authenticate with API
const response = await client.authenticate({
    resource: 'https://api.example.com/protected',
    method: 'GET'
});

if (response.ok) {
    const data = await response.json();
    console.log('βœ… Authenticated as:', client.getAddress());
    console.log('Data:', data);
} else {
    console.error('❌ Authentication failed:', response.status);
}

Express Server

import express from 'express';
import { createOpenKit403, inMemoryLRU } from '@openkitx403/server';

const app = express();

const openkit = createOpenKit403({
    issuer: 'my-api-v1',
    audience: 'https://api.example.com',
    ttlSeconds: 60,
    bindMethodPath: true,
    replayStore: inMemoryLRU()
});

app.use(openkit.middleware());

app.get('/protected', (req, res) => {
const user = req.openkitx403User;
res.json({ message: 'Hello!', wallet: user.address });
});

app.listen(3000);

FastAPI Server

from fastapi import FastAPI, Depends
from openkitx403 import OpenKit403Middleware, require_openkitx403_user

app = FastAPI()

app.add_middleware(
OpenKit403Middleware,
    audience="https://api.example.com",
    issuer="my-api-v1",
    ttl_seconds=60,
    bind_method_path=True,
    replay_backend="memory"
)

@app.get("/protected")
async def protected(user=Depends(require_openkitx403_user)):
    return {"message": "Hello!", "wallet": user.address}

🎯 How It Works

  1. Client requests a protected resource β†’ 403 Forbidden
  2. Server responds with WWW-Authenticate: OpenKitx403 ... header containing a challenge
  3. Client asks user's Solana wallet (Phantom/Backpack/Solflare) to sign the challenge
  4. Client re-sends request with Authorization: OpenKitx403 ... header
  5. Server verifies signature and grants access β†’ 200 OK

Client Server | | | GET /protected | |----------------------------->| | | | 403 + Challenge | |<-----------------------------| | | | [User signs with wallet] | | | | GET /protected + Auth | |----------------------------->| | | | 200 OK + Data | |<-----------------------------|

Security Features

  • Short-lived challenges (60s default TTL)
  • Replay protection via nonce store
  • Method/path binding prevents cross-endpoint replay
  • Origin/User-Agent binding (optional)
  • Clock skew tolerance (Β±120s default)
  • Token-gating support for NFT/SPL token requirements

Documentation

Wallet Compatibility

Wallet Browser Mobile Status
Phantom βœ… ⚠️ Via WalletConnect Supported
Backpack βœ… ❌ Supported
Solflare βœ… ⚠️ Via WalletConnect Supported

AI Agent & LangChain Integration

OpenKitx403 supports autonomous agents and LangChain tools:

import { SolanaWalletAuthTool } from '@openkitx403/langchain';
import { initializeAgentExecutorWithOptions } from 'langchain/agents';

const tools = [new SolanaWalletAuthTool()];
const executor = await initializeAgentExecutorWithOptions(tools, model, {
    agentType: "zero-shot-react-description"
});

const result = await executor.call({
    input: "Connect my wallet and fetch my NFT collection"
});

See USAGE_EXAMPLES.md for complete examples.

πŸ“Š Package Structure

openkitx403/ β”œβ”€β”€ packages/ β”‚ β”œβ”€β”€ ts-client/ # Browser & Node.js SDK β”‚ β”œβ”€β”€ ts-server/ # Express & Fastify middleware β”‚ β”œβ”€β”€ py-server/ # FastAPI middleware β”‚ └── examples/ # Demo applications β”œβ”€β”€ docs/ # Protocol specification β”œβ”€β”€ tests/ # Test suites └── USAGE_EXAMPLES.md # Complete usage guide

πŸ§ͺ Testing

Install dependencies
npm install

Build all packages
npm run build

Run tests
npm run test
npm run test --workspace=packages/ts-client
npm run test --workspace=packages/ts-server

Python tests
cd packages/py-server
pytest

Advanced Features

Token Gating

const openkit = createOpenKit403({
    issuer: 'my-api',
    audience: 'https://api.example.com',
    tokenGate: async (address: string) => {
        // Check if wallet holds required NFT/token
        const hasToken = await checkTokenHolding(address);
        return hasToken;
    }
});

Custom Replay Store

class RedisReplayStore implements ReplayStore {
    async check(key: string, ttl: number): Promise<boolean> {
        return await redis.exists(key);
    }

    async store(key: string, ttl: number): Promise<void> {
        await redis.setex(key, ttl, '1');
    }
}

const openkit = createOpenKit403({
    replayStore: new RedisReplayStore()
});

Contributing

Contributions welcome! Please read CONTRIBUTING.md first.

πŸ“„ License

MIT License - see LICENSE

Acknowledgments

Inspired by the "HTTP-native + wallet + open" philosophy, OpenKitx403 is built from scratch with:

  • Different header names and message format
  • Enhanced security model
  • Production-grade implementations
  • Comprehensive documentation

Links

Support


Built with ❀️ for the Solana ecosystem

About

HTTP-native wallet authentication for Solana. Uses HTTP 403 as the primitive. Wallets sign challenges. No custom protocols. No account secrets.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors