# Technical Documentation: jnsahaj/tweakcn

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/jnsahaj/tweakcn)

### Overview (`README.md`)

<div align="center">
  <h1>tweakcn.com</h1>
</div>

<div align="center">
  <a href="https://vercel.com/oss">
    <img alt="Vercel OSS Program" src="https://vercel.com/oss/program-badge.svg" />
  </a>
  <br />
  <br />
  <a href="https://discord.gg/Phs4u2NM3n" target="_blank">
    <img alt="Discord" src="https://img.shields.io/discord/1353416868769173576?style=for-the-badge&logo=discord&logoColor=%23ffffff">
  </a>
  <img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/jnsahaj/tweakcn?style=for-the-badge&logo=github">
  <a href="https://x.com/iamsahaj_xyz">
    <img alt="X (formerly Twitter) URL" src="https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fiamsahaj_xyz&style=for-the-badge&logo=x&label=%40iamsahaj_xyz&color=%2300000000" />
  </a>
</div>

<br />

**[tweakcn](https://tweakcn.com)** is a powerful Visual Theme Editor for tailwind CSS & shadcn/ui components. It comes with Beautiful theme presets to get started, while aiming to offer advanced customisation for each aspect of your UI



## Motivation

Websites made with shadcn/ui famously look the same. tweakcn is a tool that helps you customize shadcn/ui components visually, to make your components stand-out. The goal is to build a platform where a user can discover endless customization options and then have the ability to put their own twist on it.

## Current Features

You can find the full feature list here: https://tweakcn.com/#features

## Run Locally

**IMPORTANT: For contributions, please see [CONTRIBUTING.md](CONTRIBUTING.md).**

### Prerequisites

- Node.js 18+
- npm / yarn / pnpm

### Installation

1. Clone the repository:

```bash
git clone https://github.com/jnsahaj/tweakcn.git
cd tweakcn
```

2. Install dependencies:

```bash
npm install
```

3. Start the development server:

```bash
npm run dev
```

4. Open [http://localhost:3000](http://localhost:3000) in your browser.

## Contributors

<a href="https://github.com/jnsahaj/tweakcn/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=jnsahaj/tweakcn" />
</a>

Made with [contrib.rocks](https://contrib.rocks).

### Interested in Contributing?

Contributions are welcome! Please feel free to submit a Pull Request.

# Star History

<p align="center">
  <a target="_blank" href="https://star-history.com/#jnsahaj/tweakcn&Date">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=jnsahaj/tweakcn&type=Date&theme=dark">
      <img alt="GitHub Star History for jnsahaj/tweakcn" src="https://api.star-history.com/svg?repos=jnsahaj/tweakcn&type=Date">
    </picture>
  </a>
</p>

---

### Oauth Api (`docs/oauth-api.md`)

# OAuth 2.0 API

tweakcn exposes an OAuth 2.0 API so external apps can authenticate users and access their data.

## Registering an app

Register an OAuth app via the CLI script:

```bash
npx tsx scripts/create-oauth-app.ts \
  --name "My App" \
  --redirect-uris "https://myapp.com/callback" \
  --scopes "themes:read,profile:read" \
  --description "Optional description"
```

This outputs a `client_id` and `client_secret`. The secret is shown once and cannot be retrieved later.

## Authorization flow

Standard OAuth 2.0 Authorization Code flow. PKCE is supported but optional.

### 1. Redirect the user to authorize

```
GET https://tweakcn.com/api/oauth/authorize
  ?client_id=CLIENT_ID
  &redirect_uri=https://myapp.com/callback
  &response_type=code
  &scope=themes:read profile:read
  &state=RANDOM_STRING
```

If the user is not signed in, they'll be shown a sign-in page. After signing in, they're redirected to your `redirect_uri` with an authorization code:

```
https://myapp.com/callback?code=AUTH_CODE&state=RANDOM_STRING
```

### 2. Exchange the code for tokens

```bash
curl -X POST https://tweakcn.com/api/oauth/token \
  -d grant_type=authorization_code \
  -d client_id=CLIENT_ID \
  -d client_secret=CLIENT_SECRET \
  -d code=AUTH_CODE \
  -d redirect_uri=https://myapp.com/callback
```

Response:

```json
{
  "access_token": "...",
  "refresh_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "themes:read profile:read"
}
```

### 3. Call the API

Pass the access token as a Bearer token:

```bash
curl https://tweakcn.com/api/v1/themes \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

### 4. Refresh tokens

Access tokens expire after 1 hour. Use the refresh token to get a new pair:

```bash
curl -X POST https://tweakcn.com/api/oauth/token \
  -d grant_type=refresh_token \
  -d client_id=CLIENT_ID \
  -d client_secret=CLIENT_SECRET \
  -d refresh_token=REFRESH_TOKEN
```

### 5. Revoke tokens

```bash
curl -X POST https://tweakcn.com/api/oauth/revoke \
  -d token=ACCESS_OR_REFRESH_TOKEN
```

## Using with Better Auth's genericOAuth

tweakcn works as a provider with Better Auth's `genericOAuth` plugin:

```typescript
// server
import { genericOAuth } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    genericOAuth({
      config: [
        {
          providerId: "tweakcn",
          clientId: process.env.TWEAKCN_CLIENT_ID,
          clientSecret: process.env.TWEAKCN_CLIENT_SECRET,
          authorizationUrl: "https://tweakcn.com/api/oauth/authorize",
          tokenUrl: "https://tweakcn.com/api/oauth/token",
          userInfoUrl: "https://tweakcn.com/api/oauth/userinfo",
          scopes: ["themes:read", "profile:read"],
        },
      ],
    }),
  ],
});
```

```typescript
// client
import { genericOAuthClient } from "better-auth/client/plugins";

const authClient = createAuthClient({
  plugins: [genericOAuthClient()],
});

await authClient.signIn.oauth2({
  providerId: "tweakcn",
  callbackURL: "/dashboard",
});
```

## API endpoints

All endpoints require `Authorization: Bearer <access_token>`.

### `GET /api/oauth/userinfo`

OIDC-compatible userinfo endpoint. Returns flat user fields. Requires `profile:read` scope.

```json
{
  "sub": "user_123",
  "name": "Jane Doe",
  "email": "jane@example.com",
  "picture": "https://..."
}
```

### `GET /api/v1/me`

Returns the authenticated user's profile. Requires `profile:read` scope.

```json
{
  "data": {
    "id": "...",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "image": "https://..."
  }
}
```

### `GET /api/v1/themes`

Returns all themes owned by the authenticated user. Requires `themes:read` scope.

```json
{
  "data": [
    {
      "id": "...",
      "name": "My Theme",
      "styles": { ... },
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ]
}
```

### `GET /api/v1/themes/:themeId`

Returns a single theme by ID. Only returns themes owned by the authenticated user. Requires `themes:read` scope.

## Scopes

| Scope | Description |
|-------|-------------|
| `themes:read` | Read the user's saved themes |
| `profile:read` | Read the user's profile (name, email, avatar) |

## PKCE support

For public clients (e.g. SPAs, mobile apps), use PKCE by adding `code_challenge` and `code_challenge_method=S256` to the authorize request, then `code_verifier` when exchanging the code.

## Error responses

All error responses follow the OAuth 2.0 spec:

```json
{
  "error": "invalid_token",
  "error_description": "Invalid or expired access token"
}
```

---

--- METRICS ---
- Files Extracted: 2
- Estimated Token Budget: ~1824 tokens
- Canonical Reference: https://codewiki.google/github.com/jnsahaj/tweakcn
