Files
modrinth/packages/api-client
ef4044534f feat: update auth flow (#5790)
* Backend routes for choosing username in OAuth flow

* fix up oauth flow routes

* improve URL-related OAuth code

* Use user-provided callback addr instead of SELF_ADDR

* Revert "Use user-provided callback addr instead of SELF_ADDR"

This reverts commit 7ea0635d86.

* fix flow

* fix: backend response for create oauth account

* feat: new auth flow (#5840)

* update auth with new designs

* refactor: auth.js to auth.ts

* refactor: componentize auth pages

* fix: auth pages height

* feat: initial implementation of new sign-in oauth

* fix create account flow

* fix checkbox

* remove hard coded username

* implement create user validation endpoint and add more specific error responses

* feat: implement under 13 DOB guard and email/password validation route

* fix: TOCTOU issue

* refactor: pnpm prepr

* fix: make sure staging uses staging

* fix: hcaptcha styles

* fix: copy

* remove: auth/welcome page as its no longer used

* refactor: bring root page card styles into individual components and use tailwind

* fix: account settings modals to use new modal and fix lots of bad styles

* refactor: pnpm prepr

* feat: implement last signed in indicator

* fix: append number when generated name from email is taken

* refactor: pnpm prepr

* fix: last sign in badge color

* fix: qa issues

* refactor: pnpm prepr

* fix: hover effect on native date picker

* chore: temp staging undo

* Revert "chore: temp staging undo"

This reverts commit cad6bd4f92.

* feat: handle app create account

* fix: last signed in style

* fix: add initOnMounted for SSR race

* refactor: use typescript

* refactor: pnpm prepr

* refactor: use typescript for reset-password

* refactor: convert verify-email to use typescript

* refactor: convert authorize.vue to use typescript

* fix: authorize.vue error states

* feat: small style updates

* feat: implement date picker component

* feat: improve UX and styles for range select

* refactor: pnpm prepr

* fix: range select border styles

* feat: implement date picker component in create account

* feat: implement preserve date for date picker

* update rust toolchain

* increase recursion limit

* fix: date picker can be null

* fix: calculate age based on user's timezone

* fix: number input icons color

* fix: date picker icons

* feat: improve styles

* fix: add width on date

* fix: hover color bad on number input

* fix lints

* feat: add default date open view

* fmt

* fix: account.vue

* fix: remove default date to open 13 years ago

* fix: edit copy on info banner

* fix: cannot hover over project card tooltip items (#6071)

fix: cannot hover over project cards

* feat: improve add dependency flow (#6075)

* fix: shadow on nav

* feat: improve add dependency flow

* feat: update suggested dependency style

* feat: update dependency rows to use version number and update styles

* feat: implement combobox select searched text on focus

* feat: add Tabs.vue

* feat: update nav tabs to use tabs

* feat: improve project search dropdown

* fix: dependency search not clearing inbound query

* fix: combobox no options open state bug

* feat: improve dependency project and version search

* fix: open modrinth project links in the app (#6072)

* pin tanstack versions + set pnpm min age to 7 days

* squash commits

* fix: 2 factor auth enter code screen styles

* update copy

* update copy

* improve reset password

* feat: update sign in screen

* fix: unused import

* Merge branch 'main' into boris/dev-908-backend-changes

* Revert "Merge branch 'main' into boris/dev-908-backend-changes"

This reverts commit b9b03796e3.

* fix: add stroke

* feat: add passkey support (#6375)

* feat: add passkey backend

* feat: passkey frontend

* invalidate sessions on compromised passkey

* chore: run sqlx prepare

* fix: make passkey button use both collumns to prevent empty space

* fix: correctly verify max passkeys in finish route

* fix: use structs for response

* fix: add rp name default

* style: use web::Json

* fmt

* feat: improve manage passkeys UI

* fix copy

* pnpm prepr

---------

Co-authored-by: tdgao <mr.trumgao@gmail.com>
Co-authored-by: Truman Gao <106889354+tdgao@users.noreply.github.com>
Co-authored-by: Michael H. <michael@iptables.sh>
Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
Co-authored-by: Calum H. <calum@modrinth.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
Co-authored-by: DeDiamondPro <67508414+DeDiamondPro@users.noreply.github.com>
2026-06-25 20:36:19 +00:00
..
2026-06-25 20:36:19 +00:00

@modrinth/api-client

TypeScript License: LGPL-3.0

Platform-agnostic TypeScript client for Modrinth's API across Node.js, browsers, Nuxt, and Tauri.

⚠️ We use this internally to power modrinth.com, Modrinth App, and Modrinth Hosting frontends. It may break without any notice, but you are welcome to use it.

Installation

pnpm add @modrinth/api-client

Tauri apps also need the optional peer dependency:

pnpm add @modrinth/api-client @tauri-apps/plugin-http

Usage

Generic Node.js or Browser Client

import { AuthFeature, GenericModrinthClient, type Labrinth } from '@modrinth/api-client'

const client = new GenericModrinthClient({
	userAgent: 'my-app/1.0.0',
	features: [new AuthFeature({ token: process.env.MODRINTH_TOKEN })],
})

const project: Labrinth.Projects.v2.Project = await client.labrinth.projects_v2.get('sodium')
const members = await client.labrinth.projects_v3.getMembers(project.id)

You can still make direct requests through the same platform layer:

const project = await client.request<Labrinth.Projects.v2.Project>('/project/sodium', {
	api: 'labrinth',
	version: 2,
})

Nuxt

import { AuthFeature, CircuitBreakerFeature, NuxtCircuitBreakerStorage, NuxtModrinthClient } from '@modrinth/api-client'

export const useModrinthClient = async () => {
	const config = useRuntimeConfig()

	return new NuxtModrinthClient({
		userAgent: 'my-nuxt-app/1.0.0',
		rateLimitKey: import.meta.server ? config.rateLimitKey : undefined,
		features: [
			new AuthFeature({
				token: process.env.MODRINTH_TOKEN,
			}),
			new CircuitBreakerFeature({
				storage: new NuxtCircuitBreakerStorage(),
			}),
		],
	})
}

Tauri

import { getVersion } from '@tauri-apps/api/app'
import { AuthFeature, TauriModrinthClient } from '@modrinth/api-client'

const client = new TauriModrinthClient({
	userAgent: async () => `modrinth/theseus/${await getVersion()} (support@modrinth.com)`,
	features: [new AuthFeature({ token: process.env.MODRINTH_TOKEN })],
})

const project = await client.labrinth.projects_v2.get('sodium')

API Modules

Modules are available as nested properties on the client:

client.labrinth.projects_v2
client.labrinth.projects_v3
client.labrinth.versions_v3

Types are exported from the package root:

import type { Labrinth } from '@modrinth/api-client'

const project: Labrinth.Projects.v3.Project = await client.labrinth.projects_v3.get('sodium')

Modrinth Hosting API Modules

  • These modules are internal to Modrinth and are only supported inside the Modrinth Hosting panel in Modrinth App and on modrinth.com. They should not be expected to work in third-party clients today. We are discussing how to safely expose access to your own server through these APIs in the future.

Base URLs

By default, the client uses Modrinth production services:

  • labrinthBaseUrl: https://api.modrinth.com

Override them for staging or custom deployments:

const client = new GenericModrinthClient({
	userAgent: 'my-app/1.0.0',
	labrinthBaseUrl: 'https://staging-api.modrinth.com',
})

External APIs can be targeted per request by passing a full URL as api and disabling auth:

await client.request('/endpoint', {
	api: 'https://example.com',
	version: 1,
	skipAuth: true,
})

Features

Features wrap requests before they reach the platform implementation:

import { AuthFeature, CircuitBreakerFeature, RetryFeature } from '@modrinth/api-client'

const client = new GenericModrinthClient({
	features: [new AuthFeature({ token: async () => process.env.MODRINTH_TOKEN }), new RetryFeature({ maxAttempts: 3, backoffStrategy: 'exponential' }), new CircuitBreakerFeature({ maxFailures: 3, resetTimeout: 30_000 })],
})

Built-in features include authentication, node auth, retries, circuit breaking, panel version headers, and verbose logging.

Uploads

Upload endpoints return an UploadHandle<T> with progress and cancellation support:

const upload = client.kyros.files_v0.uploadFile(path, file)

upload.onProgress(({ progress }) => {
	console.log(Math.round(progress * 100))
})

await upload.promise

Uploads use XMLHttpRequest for progress tracking and are only available in browser-capable contexts. NuxtModrinthClient.upload() throws during SSR.

Third-Party API Typings

  • This package also includes some third-party API modules and typings used by Modrinth internals. They are not part of the stable public API surface and should be used at your own risk.

Development

pnpm --filter @modrinth/api-client build
pnpm --filter @modrinth/api-client lint
# or pnpm prepr:frontend:lib in turborepo root.

When adding a module, add it to src/modules/index.ts so it is included in the typed client structure.

License

Licensed under LGPL-3.0. See LICENSE.