Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
02b975b
add external auth columns to user table
MatthiasKainer Oct 27, 2025
5b5a840
add environment variables draft for external authentication
MatthiasKainer Oct 27, 2025
521aac8
First draft of external authentication utilities
MatthiasKainer Oct 27, 2025
42eef36
add OAuth provider support
MatthiasKainer Oct 27, 2025
7cdb125
add hybrid authentication support
MatthiasKainer Oct 27, 2025
64b2a7f
add external authentication endpoints
MatthiasKainer Oct 27, 2025
9bbcd4e
Vibe coded react component for account linking. Now for the test
MatthiasKainer Oct 27, 2025
7ef69cc
Adding it to the login form too because that helps with testing
MatthiasKainer Oct 27, 2025
b02d070
Add documentation that proved working during testing
MatthiasKainer Oct 27, 2025
62328b8
Merge pull request #2 from inxm-ai/feat/pluggable-auth
MatthiasKainer Oct 27, 2025
dc54f48
Fix linting errors
MatthiasKainer Oct 27, 2025
e6d9c7c
Added standalone deployment and docker image
MatthiasKainer Oct 27, 2025
153a7ba
Add env file that drizzle needs
MatthiasKainer Oct 27, 2025
77ce26e
Add first rudimentary api key based authentication
MatthiasKainer Oct 27, 2025
55ad881
Can't use any
MatthiasKainer Oct 27, 2025
9337185
Allow non ssl for pg also on sandboxed qa environments
MatthiasKainer Oct 27, 2025
eec6f36
Add proxy auth to mcp
MatthiasKainer Oct 29, 2025
25c4b8c
First authz service
MatthiasKainer Oct 29, 2025
360b136
Added role based auth to api and report service
MatthiasKainer Oct 29, 2025
4b301f3
Fixed linting error
MatthiasKainer Oct 29, 2025
3031752
Use PGSSLMODE for checking postgres ssl status
MatthiasKainer Oct 29, 2025
516005c
Set basePath via env
MatthiasKainer Oct 30, 2025
49a9c60
Prefix assets as well
MatthiasKainer Oct 30, 2025
05d1042
Add auth headers to allowed headers
MatthiasKainer Oct 30, 2025
9a4eeb0
Create hook for auth in proxy mode
MatthiasKainer Oct 30, 2025
7c133e5
Trying to avoid eager redirect in proxy mode
MatthiasKainer Oct 30, 2025
4da27d3
Return structured content
MatthiasKainer Oct 31, 2025
9425c9d
Some package hygene
MatthiasKainer Oct 31, 2025
ea36a83
Register tools with output schema
MatthiasKainer Oct 31, 2025
897cb4a
Add userId to schema
MatthiasKainer Jan 19, 2026
598ece0
Add userId to schema in projects too
MatthiasKainer Jan 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,82 @@ LOOPS_EMAIL_VERIFICATION_TEMPLATE_ID=
# Seed User ID
# This is the user ID that will be used to seed the database with sample data
SEED_USER_ID=test-user-123

# External Authentication Configuration Examples

# ============================================================================
# EXTERNAL AUTH MODE
# ============================================================================

# Options: "better-auth", "proxy", "disabled"
EXTERNAL_AUTH_MODE=disabled

# Provider selection (better-auth mode only)
# Options: "google", "github", "entra", "custom"
#EXTERNAL_AUTH_PROVIDER=google

# --- Google OAuth ---
# Create credentials: https://console.cloud.google.com/
# Redirect URI: https://your-domain.com/api/auth/callback/google
#OAUTH_GOOGLE_CLIENT_ID=123456789-abcdef.apps.googleusercontent.com
#OAUTH_GOOGLE_CLIENT_SECRET=GOCSPX-your-secret-here

# --- GitHub OAuth ---
# Create OAuth App: https://github.com/settings/developers
# Callback URL: https://your-domain.com/api/auth/callback/github
#OAUTH_GITHUB_CLIENT_ID=Iv1.1234567890abcdef
#OAUTH_GITHUB_CLIENT_SECRET=your-github-client-secret

# --- Microsoft Entra ID (Azure AD) ---
# Register app: https://portal.azure.com/
# Redirect URI: https://your-domain.com/api/auth/callback/microsoft-entra-id
#OAUTH_ENTRA_CLIENT_ID=12345678-1234-1234-1234-123456789abc
#OAUTH_ENTRA_CLIENT_SECRET=your-entra-secret
#OAUTH_ENTRA_TENANT_ID=your-tenant-id

# --- Custom OIDC Provider ---
# For any OAuth 2.0 / OpenID Connect provider
#OAUTH_CUSTOM_AUTHORIZATION_URL=https://provider.com/oauth/authorize
#OAUTH_CUSTOM_TOKEN_URL=https://provider.com/oauth/token
#OAUTH_CUSTOM_USERINFO_URL=https://provider.com/oauth/userinfo
#OAUTH_CUSTOM_CLIENT_ID=your-client-id
#OAUTH_CUSTOM_CLIENT_SECRET=your-client-secret

# ============================================================================
# PROXY MODE
# ============================================================================

# Header names (defaults shown, customize if your proxy uses different headers)
#PROXY_USER_HEADER=x-auth-request-user
#PROXY_EMAIL_HEADER=x-auth-request-email
#PROXY_JWT_HEADER=x-auth-request-jwt

# JWT Verification

# Option 1: JWKS URL (recommended for production)
# The proxy should expose a JWKS endpoint with public keys
#PROXY_JWT_JWKS_URL=https://your-proxy.com/.well-known/jwks.json

# Option 2: Static Public Key (PEM format)
# Use this if proxy signs JWTs with a static key pair
#PROXY_JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
#MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
#-----END PUBLIC KEY-----"

# JWT Claims Validation (recommended)
#PROXY_JWT_ISSUER=https://your-proxy.com
#PROXY_JWT_AUDIENCE=timetracker-mcp

# ============================================================================
# EXTERNAL AUTH POLICIES
# ============================================================================

# Auto-create local user on first external login
# true: Create new user automatically (recommended)
# false: Only allow login for existing users
EXTERNAL_CREATE_LOCAL_USER=true

# Account linking policy
# auto: Automatically link external accounts by matching email (recommended)
# require-manual-link: Users must manually link accounts via UI
EXTERNAL_LINKING_POLICY=auto
66 changes: 66 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat postgresql-client
WORKDIR /app

# Install pnpm
RUN npm install -g pnpm

# Copy package files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml* ./
RUN pnpm install --frozen-lockfile

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Set environment variables for build
ENV NEXT_TELEMETRY_DISABLED=1
ENV SKIP_ENV_VALIDATION=1

# Install pnpm
RUN npm install -g pnpm

# Build the Next.js application
RUN pnpm build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Install pnpm and postgresql-client for migrations
RUN npm install -g pnpm
RUN apk add --no-cache postgresql-client

# Copy necessary files from builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/drizzle ./drizzle
COPY --from=builder /app/lib/env.ts ./lib/env.ts
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/drizzle.config.ts ./drizzle.config.ts

RUN chown -R nextjs:nodejs /app

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

# Start the application
CMD ["node", "server.js"]
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ A **conversational-first time tracking platform** built on the **Model Context P
- **Multi-User with Shared Resources** — individual time tracking with shared clients and projects for seamless team collaboration.
- **Data Integrity Protection** — clients and projects with tracked time cannot be deactivated, preserving historical data.
- **Patched Authentication** — uses [Better Auth](https://github.com/better-auth/better-auth) with our patch ([PR #3091](https://github.com/better-auth/better-auth/pull/3091)) adding enhanced PKCE support described in `docs/better-auth-patch.md`.
- **External OAuth Support** — integrate Google, GitHub, Microsoft Entra ID, or custom OAuth/OIDC providers; supports OAuth proxy mode for enterprise deployments. See [External Auth Guide](docs/EXTERNAL_AUTH.md).
- **Open User Registration** — by default, anyone can create an account through the signup page at `/app/signup`.
- **Optional Email Verification** — secure user registration with email verification via [Loops.js](https://loops.so) (optional feature).
- **Dark/Light Theme** — implemented with `next-themes` & CSS variables.
Expand Down Expand Up @@ -202,6 +203,27 @@ By default, email verification is disabled (`ENABLE_EMAIL_VERIFICATION=false` in

For more details on authentication configuration options, refer to the [Better Auth documentation](https://www.better-auth.com/docs/reference/options).

### External OAuth Authentication

TimeTracker MCP supports external OAuth/OIDC authentication providers through two modes:

1. **Better Auth Integration** — OAuth providers (Google, GitHub, Microsoft Entra ID, custom OIDC) integrated directly
2. **OAuth Proxy Mode** — Use an external OAuth proxy with signed JWT headers for enterprise deployments
3. **Disabled** — Default mode with email/password only

For complete configuration instructions, see **[External Authentication Guide](docs/EXTERNAL_AUTH.md)**.

Quick configuration:
```bash
# Enable external auth
EXTERNAL_AUTH_MODE=better-auth # or "proxy" or "disabled"

# For Better Auth mode - configure OAuth provider
EXTERNAL_AUTH_PROVIDER=google
OAUTH_GOOGLE_CLIENT_ID=your-client-id
OAUTH_GOOGLE_CLIENT_SECRET=your-client-secret
```

### Optional Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
Expand All @@ -210,6 +232,26 @@ For more details on authentication configuration options, refer to the [Better A
| `LOOPS_API_KEY` | Loops.js API key (required if email verification is enabled) | Not set |
| `LOOPS_EMAIL_VERIFICATION_TEMPLATE_ID` | Custom email template ID for verification emails | Uses default template |

### MCP API Key (non-OAuth access)

You can optionally expose the MCP tools to trusted clients using a static API key instead of the OAuth flow. This is useful for server-to-server integrations or when you control the client environment and cannot perform OAuth.

Environment variables:

- `MCP_API_KEY` — the secret token that your client will send.
- `MCP_API_USER_ID` — (optional) local user id to associate requests authenticated with `MCP_API_KEY`. If not provided the server falls back to `SEED_USER_ID` or a generic `service-user` id.

How to send the key:

- Header: `x-api-key: <your-key>`
- Or: `Authorization: Bearer <your-key>`

Security notes:

- Treat `MCP_API_KEY` like any other secret. Do not commit it to repos or expose it in client-side code.
- For production consider rotating keys, using per-client keys, IP allowlists, short-lived tokens, or DB-backed API keys with create/delete endpoints.


> **Note** You can create a free Postgres database on [Neon](https://neon.tech) and a free Redis database on [Upstash](https://upstash.com). Redis is optional, but recommended for production use.

## Optional Features
Expand Down
Loading