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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@venn-lang/auth

v0.7.5

Published

The auth namespace: build the header a request needs, or fetch a token for it.

Readme

@venn-lang/auth

The auth namespace: build the header a request needs, or fetch a token for it.

Six of the seven verbs are pure computation, headers, signatures and codes worked out from what you hand them. The seventh, auth.oauth2, is the one that talks to a token endpoint, and it goes through the AuthClient port so the exchange is injected rather than hard-wired. Real cryptography uses the global Web Crypto (crypto.subtle), so nothing here imports node:*.

Install

Nothing to install. @venn-lang/auth is part of the standard library, and the CLI and the language server both load @venn-lang/stdlib, which lists every stdlib plugin. A file reaches the namespace with one line.

import { auth } from "venn/auth"

Usage

module demo.auth

import { auth } from "venn/auth"
import { assert } from "venn/assert"

flow "Signed in" {
  step "a bearer header carries the token" {
    const header = auth.bearer "tok123"
    expect header.Authorization == "Bearer tok123"
  }

  step "a service account gets a token" {
    const token = auth.oauth2 "svc-account" { grant: "client_credentials", scope: "orders:write" }
    expect token.expires_in > 0
  }
}

Verbs

| Verb | Call | Result | | --- | --- | --- | | auth.bearer | auth.bearer "tok123" | auth.Headers | | auth.basic | auth.basic "alice" "s3cret" | auth.Headers | | auth.apikey | auth.apikey "KEY" { header: "X-Token" } | auth.Headers | | auth.hmac | auth.hmac "s3cret" "payload" { algo: "sha512" } | string, lowercase hex | | auth.totp | auth.totp "seed" { at: 0, period: 30, digits: 6 } | string | | auth.jwt | auth.jwt { payload: { sub: "42" }, secret: "k" } | string | | auth.oauth2 | auth.oauth2 "svc-account" { grant: "client_credentials" } | auth.Token |

bearer returns { Authorization: "Bearer <token>" }.

basic base64-encodes the UTF-8 bytes of user:pass into { Authorization: "Basic <…>" }, which is what RFC 7617 §2 requires. It used to call btoa on the string, which encodes latin-1: auth.basic "user" "señha" went out as dXNlcjpzZfFoYQ== rather than dXNlcjpzZcOxaGE=, so the far end read a different password, answered 401, and nothing here said why. A password outside latin-1 threw a DOMException with no code and no line at all. http.get "…" { basic: … } uses the same encoder, so the two agree byte for byte.

apikey puts the key under a header of your choosing. The header option defaults to X-API-Key, so auth.apikey "KEY" gives { "X-API-Key": "KEY" }.

hmac takes the secret first and the payload second, so auth.hmac "s3cret" "payload" keys the HMAC with s3cret. The algo option accepts sha1, sha256, sha384 and sha512, case and dashes ignored. A name it does not recognise is refused with VN7005: signing a typo with SHA-256 produces a signature nothing verifies and says nothing about why. That list of names, and that refusal, are the ones crypto.hmac uses; there is one of each in the repository.

totp computes an RFC 6238 code and is deterministic for a fixed at, which makes it usable in a test. at is the time to compute at and period the step, both in seconds; digits defaults to 6 and the result is zero-padded, which is why it is a string and not a number.

jwt takes nothing positionally. payload and secret are required options, header is optional and is merged over the default { alg: "HS256", typ: "JWT" }. alg chooses the signature, not just what the token claims: { header: { alg: "HS512" } } is signed with SHA-512. It used to write the caller's alg into the signed bytes and sign with SHA-256 whatever it said, so crypto.jwt.verify read the claim, hashed with SHA-512 and answered false for a token nothing had tampered with. An alg no HMAC digest answers to is refused with VN7005 rather than minting a token nothing can check.

oauth2 takes the principal positionally and grant, tokenUrl, scope and refresh as options. It is the only verb here that reaches a port.

Where the digests come from

hmac, totp and jwt reach CryptoEnginePort for every digest, the same port crypto.hmac and crypto.jwt.sign use, declared in @venn-lang/sdk because a plugin may not depend on another plugin. They used to call the global crypto.subtle directly, which meant a host that bound createFakeCryptoEngine made crypto.* reproducible and left auth.* on real WebCrypto: half a run replayable, half not. A test that swaps the engine in now reaches all three.

The types it publishes

| Type | Shape | | --- | --- | | auth.Headers | map<string>. A map rather than a record, because auth.apikey names its own header and the key is only known at the call site. | | auth.Token | { access_token, token_type, expires_in }, the OAuth2 wire shape. |

The AuthClient port

| | | | --- | --- | | id | venn.port.auth-client | | version | 1 | | requires | net | | methods | token |

Two implementations ship together, which is what makes this a port rather than a module with a good interface:

  • createFakeAuthClient() returns a canned token derived from the principal, with no network. This is the one @venn-lang/stdlib binds, so auth.oauth2 resolves offline. Pass { token: { expires_in: 60 } } to override any field of what it hands back.
  • createRealAuthClient() is a stub. Every call throws a VennError with code VN8090, because this repository is the language and ships no live token exchange.

Both run the same conformance suite, authClientConformance in src/clients/auth-client.suite.ts: a token resolves with a string access_token, a string token_type and a numeric expires_in.

The plugin as a whole declares requires: ["net"], so a host without the net capability is refused with a legible diagnostic before the run starts, rather than failing somewhere inside auth.oauth2.

API

| Export | What it is | | --- | --- | | authPlugin | The plugin definition: namespace auth, requires: ["net"]. Also the default export. | | authActions | The seven action definitions: bearer, basic, apikey, hmac, totp, jwt, oauth2. | | AuthClientPort | The port descriptor. | | AuthClient | The port interface: token(request). | | OAuthTokenRequest | What the port is asked: principal, and the optional grant, tokenUrl, scope, refresh. | | OAuthToken | What it answers: { access_token, token_type, expires_in }. | | createFakeAuthClient({ token? }) | The deterministic double. | | createRealAuthClient() | The real client, stubbed to throw VN8090. | | authTypeDefs | The TypeSpecs for auth.Headers and auth.Token, which the checker and the LSP read. |

Binding a different client means one entry in the runner's port list:

import { AuthClientPort, createFakeAuthClient } from "@venn-lang/auth";
import { createRunner } from "@venn-lang/runtime";

const runner = createRunner({
  host,
  plugins,
  sink,
  uri,
  ports: [{ port: AuthClientPort, impl: createFakeAuthClient() }],
});

See also