npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

stint-signer

v0.5.7

Published

Short-lived, non-custodial session signer using passkeys for Cosmos SDK

Readme

Stint

npm version codecov Known Vulnerabilities

Zero-balance session signers for smooth Web3 UX. Post, vote, and transact without wallet popups using Passkeys + Cosmos SDK authz + feegrant modules.

⚠️ EXPERIMENTAL SOFTWARE - TESTNET ONLY

This project is experimental and has NOT undergone a security audit. Only use on testnets with test tokens that have no real value. Do not use with real funds or in production environments.

What is Stint?

Stint creates temporary signers that can perform limited actions on behalf of your main wallet without holding any funds. Perfect for social dApps, games, and frequent interactions.

How it works:

  1. Create a session signer using your device's Passkey (fingerprint/Face ID)
  2. Authorize specific actions (like posting to social networks) with spending limits
  3. Interact seamlessly - no more wallet popups for every small transaction

Your main wallet stays secure, session signers are time-limited, and you can revoke access anytime.

Why Use Stint?

Perfect for apps that need frequent, small transactions:

Social Media dApps

  • Post messages without wallet popups
  • Like/react to content instantly
  • Comment and interact seamlessly

Gaming & NFTs

  • In-game transactions and trades
  • Achievement claims and rewards
  • Tournament entries

DAOs & Governance

  • Vote on multiple proposals
  • Delegate voting power
  • Submit proposals without friction

Micro-payments

  • Content tips and donations
  • Subscription payments
  • Pay-per-use services

Installation

npm install stint-signer
# or
pnpm add stint-signer
# or
yarn add stint-signer

Quick Start

import { newSessionSigner } from 'stint-signer'

// 1. Create session signer (triggers Passkey prompt)
const sessionSigner = await newSessionSigner({
  primaryClient  // Your existing SigningStargateClient
})

// 2. Define authorized recipient for security
const authorizedRecipient = 'atone1dither123...' // Only allow sends to this address

// 3. Set up permissions (one-time setup)
const setupMessages = sessionSigner.generateDelegationMessages({
  sessionExpiration: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours
  spendLimit: { denom: 'uphoton', amount: '1000000' },   // Max 1 PHOTON
  gasLimit: { denom: 'uphoton', amount: '500000' },      // 0.5 PHOTON for gas
  allowedRecipients: [authorizedRecipient]              // Restrict to specific address
})

await primaryClient.signAndBroadcast(
  sessionSigner.primaryAddress(), 
  setupMessages, 
  'auto'
)

// 4. Now send transactions instantly! 🚀
await sessionSigner.execute.send({
  toAddress: authorizedRecipient,  // Must match allowedRecipients
  amount: [{ denom: 'uphoton', amount: '100000' }],
  memo: 'Posted via session signer!'
})

That's it! No more wallet popups for authorized transactions.

Live Example

🎯 Try the Dither Demo - Post to a decentralized social network without wallet popups!

The demo shows how to:

  • Create session signers with WebAuthn Passkeys
  • Set up permissions in one transaction
  • Post messages instantly using session signers

Basic API

Creating a Session Signer

import { newSessionSigner } from 'stint-signer'

const sessionSigner = await newSessionSigner({
  primaryClient,                    // Your SigningStargateClient
  saltName?: 'my-app',             // Optional: isolate different apps
  stintWindowHours?: 24,           // Optional: key rotation interval (default: 24 hours)
  usePreviousWindow?: false,       // Optional: use previous time window for grace period
  logger?: consoleLogger,          // Optional: enable debug logs
  keyMode?: 'passkey'              // Optional: 'passkey' (default) or 'random' (ephemeral)
})

Setting Up Permissions

// Generate permission messages
const messages = sessionSigner.generateDelegationMessages({
  sessionExpiration: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours
  spendLimit: { denom: 'uphoton', amount: '1000000' },   // Max spending
  gasLimit: { denom: 'uphoton', amount: '500000' },      // Gas allowance
  allowedRecipients: ['atone1...']  // Optional: restrict recipients
})

// Sign with your main wallet (one time)
await primaryClient.signAndBroadcast(primaryAddress, messages, 'auto')

Using Session Signers

// Send tokens instantly (no wallet popup!)
await sessionSigner.execute.send({
  toAddress: 'atone1recipient...',
  amount: [{ denom: 'uphoton', amount: '100000' }],
  memo: 'Instant transaction!'
})

// Check permissions
const hasPermission = await sessionSigner.hasAuthzGrant()
const hasGasAllowance = await sessionSigner.hasFeegrant()

Learn More

📖 Complete Guide - Advanced usage, security considerations, and detailed examples

🎯 Example App - Full working demo with Dither social network

Advanced Configuration

Window-Based Key Rotation

Stint implements automatic key rotation using time-based windows for enhanced security:

const sessionSigner = await newSessionSigner({
  primaryClient,
  saltName: 'my-app',
  
  // Key rotates every 8 hours for high-security apps
  stintWindowHours: 8,
  
  // Use previous window during transitions to avoid interruptions
  usePreviousWindow: false,
})

Window Configuration Options:

  • stintWindowHours: 1 - Hourly rotation (maximum security)
  • stintWindowHours: 8 - 8-hour rotation (high security)
  • stintWindowHours: 24 - Daily rotation (default, balanced)
  • stintWindowHours: 168 - Weekly rotation (convenience)

Grace Period Usage:

When users might be near a window boundary, use usePreviousWindow: true to access the previous time window's keys, ensuring uninterrupted access during transitions.

Debugging Window Boundaries

import { getWindowBoundaries } from 'stint-signer'

const boundaries = getWindowBoundaries(24) // 24-hour windows
console.log('Current window:', boundaries.windowNumber)
console.log('Window start:', boundaries.start)
console.log('Window end:', boundaries.end)

Key Mode Options

Stint supports two key generation modes:

Passkey Mode (Default)

  • Uses device biometrics (fingerprint/Face ID) via WebAuthn
  • Keys are deterministically derived from Passkey PRF extension
  • Survives page refreshes within the same time window
  • Most secure option

Random Mode (Fallback)

  • For environments without Passkey support
  • Generates cryptographically secure random keys
  • Keys are ephemeral - lost on page refresh
  • Use when Passkeys aren't available
// Random mode example - keys won't persist
const ephemeralSigner = await newSessionSigner({
  primaryClient,
  keyMode: 'random'  // Ephemeral keys, lost on refresh
})

Key Features

Zero-balance signers - Session signers never hold funds

Passkey security - Uses device biometrics for key derivation (in passkey mode)

Automatic key rotation - Time-windowed keys rotate automatically

Time-limited - Sessions expire automatically

Revocable - Cancel permissions anytime

Scoped permissions - Limit spending, recipients, and actions

Multi-wallet support - Works with Keplr, Leap, Cosmostation

License

Unlicense (Public Domain)