Skip to content

Latest commit

 

History

61 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RxLab Auth

A modern, full-featured authentication system built with Next.js 16 and React 19, featuring multiple authentication methods and comprehensive user management.

Features

  • 🔐 Multiple Authentication Methods

    • Email/Password authentication with secure Argon2 hashing
    • OAuth integration (configurable providers)
    • WebAuthn/Passkeys support for passwordless authentication
  • 📧 Email Services

    • Email verification
    • Password reset functionality
    • Email notifications via Resend
  • 👤 User Management

    • User registration and login
    • Account management dashboard
    • Admin panel for user administration
    • Profile customization with Identicon generation
  • 🔒 Security Features

    • Iron Session for secure session management
    • JWT token support
    • Redis-based rate limiting via Upstash
    • Scope-based permissions system

Tech Stack

  • Framework: Next.js 16 with App Router
  • UI: React 19
  • Database: Drizzle ORM with Neon Postgres (node-postgres)
  • Authentication: SimpleWebAuthn, Iron Session, Jose (JWT)
  • UI Components: shadcn/ui with base-vega style, built on @base-ui/react
  • Styling: Tailwind CSS v4
  • Email: Resend
  • Storage: Vercel Blob
  • Cache/Rate Limiting: Upstash Redis
  • Testing: Playwright for E2E tests (against an embedded Postgres cluster)
  • Package Manager: Bun

Getting Started

Prerequisites

  • Bun installed on your system
  • A Postgres database (Neon recommended)
  • Redis instance (Upstash recommended)
  • Resend API key for email functionality

Environment Variables

Create a .env.local file in the root directory with the following variables:

# Database
DATABASE_URL=postgresql://user:password@host/dbname?sslmode=require

# Application
NEXT_PUBLIC_APP_NAME=RxLab Auth
NEXT_PUBLIC_APP_URL=http://localhost:3000

# JWT Keys (generate with openssl)
JWT_PRIVATE_KEY=your_jwt_private_key
JWT_PUBLIC_KEY=your_jwt_public_key

# Email
RESEND_API_KEY=your_resend_api_key

# OAuth (optional)
OAUTH_ISSUER_URL=your_oauth_issuer_url
GITHUB_OAUTH_CLIENT_ID=your_github_oauth_client_id
GITHUB_OAUTH_CLIENT_SECRET=your_github_oauth_client_secret
GOOGLE_OAUTH_CLIENT_ID=your_google_oauth_client_id
GOOGLE_OAUTH_CLIENT_SECRET=your_google_oauth_client_secret
# Sign in with Apple (all four required; the provider stays hidden otherwise)
APPLE_OAUTH_SERVICES_ID=your_apple_services_id
APPLE_OAUTH_TEAM_ID=your_apple_team_id
APPLE_OAUTH_KEY_ID=your_apple_key_id
# base64 -i AuthKey_<KEYID>.p8 | tr -d '\n'
APPLE_OAUTH_PRIVATE_KEY=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t...
# Bundle IDs allowed for native Sign in with Apple (comma-separated)
APPLE_OAUTH_BUNDLE_IDS=com.rxlab.app

# WebAuthn
WEBAUTHN_ORIGIN=http://localhost:3000
WEBAUTHN_RP_ID=localhost
WEBAUTHN_RP_NAME=RxLab Auth

# Redis
UPSTASH_REDIS_REST_URL=your_redis_url
UPSTASH_REDIS_REST_TOKEN=your_redis_token

Register these provider callback URLs, using the same origin as OAUTH_ISSUER_URL:

https://your-auth-host/api/auth/social/github/callback
https://your-auth-host/api/auth/social/google/callback
https://your-auth-host/api/auth/social/apple/callback

Apple differs from the other two in three ways worth knowing up front:

  • There is no static client secret. The server mints a short-lived ES256 JWT from your .p8 signing key on every token exchange, so the Team ID, Key ID, Services ID and private key are all required together. Supply the key base64-encoded (base64 -i AuthKey_<KEYID>.p8 | tr -d '\n') — a single opaque line survives every shell and dashboard intact. A raw PEM, or one flattened with literal \n escapes, is accepted too.
  • The callback is a cross-site POST, not a redirect — asking Apple for the name/email scopes forces response_mode=form_post. The OAuth state cookie is therefore SameSite=None; Secure for Apple alone, which means the browser flow needs HTTPS even locally; use a tunnel rather than http://localhost.
  • Apple releases the user's name exactly once, on the first consent. It is captured then or not at all.

Configured providers appear on the web login form and in GET /api/auth/ui-schema/signin?client_id=<id> under the additive identityProviders array. Each provider includes absolute iconUrl and darkIconUrl asset URLs. Native iOS and macOS clients can use the appropriate icon for the current appearance and pass the returned authorizationParameters into /api/oauth/authorize to start the selected provider while keeping the normal authorization-code + PKCE flow back to the app.

When a verified social email matches an existing account, RxLab Auth asks the user to approve the connection before linking it. When no account exists, it asks for confirmation before creating a social-only account. Signed-in users can review and disconnect providers from the Profile page; the final sign-in method cannot be removed until another method, such as a passkey, is available.

Native Sign in with Apple

iOS and macOS clients (RxAuthSwift) use Apple's own system sheet instead of the browser flow, via a two-step pair that mirrors the native passkey routes:

POST /api/oauth/social/apple/nonce   → { session_id, nonce }
POST /api/oauth/social/apple         → OAuth token JSON

The client hashes the nonce (SHA-256, hex) into ASAuthorizationAppleIDRequest.nonce; the server verifies the resulting identity token against Apple's JWKS, pins the audience to APPLE_OAUTH_BUNDLE_IDS, re-hashes the nonce to confirm the token belongs to this request, and burns it. Because a native app has no /social/confirm page to show, an Apple-verified email that matches an existing account is linked automatically rather than prompting.

Installation

  1. Clone the repository:
git clone https://github.com/rxtech-lab/rxlab-auth.git
cd rxlab-auth
  1. Install dependencies:
bun install
  1. Set up the database:
# Generate migration files
bun db:generate

# Run migrations
bun db:migrate

# Or push schema directly (development)
bun db:push
  1. Start the development server:
bun dev

Open http://localhost:3000 to see the application.

Development Commands

bun dev          # Start development server
bun build        # Build for production
bun start        # Start production server
bun lint         # Run ESLint

# Database commands
bun db:generate  # Generate Drizzle migrations
bun db:migrate   # Run migrations
bun db:push      # Push schema to database
bun db:studio    # Open Drizzle Studio

Testing

E2E Tests

bunx playwright test              # Run all E2E tests
bunx playwright test --ui         # Interactive UI mode
bunx playwright test e2e/admin    # Run specific test suite
bunx playwright test --debug      # Debug mode

Project Structure

├── app/                    # Next.js App Router pages
│   ├── (auth)/            # Authentication routes (login, register, etc.)
│   ├── account/           # User account management
│   ├── admin/             # Admin panel
│   ├── api/               # API routes
│   └── oauth/             # OAuth integration
├── actions/               # Server actions
├── components/            # React components
│   └── ui/               # shadcn/ui components
├── lib/                   # Utilities and configuration
│   ├── auth/             # Authentication logic
│   ├── db/               # Database schema and client
│   ├── email/            # Email templates and sending
│   ├── oauth/            # OAuth providers
│   ├── redis/            # Redis client and rate limiting
│   └── webauthn/         # WebAuthn/Passkeys logic
├── e2e/                   # Playwright E2E tests
└── public/                # Static assets

Deploy on Vercel

The easiest way to deploy this app is to use the Vercel Platform:

  1. Push your code to a Git repository
  2. Import the repository to Vercel
  3. Configure your environment variables
  4. Deploy!

Make sure to set up your database and configure all required environment variables before deploying.

Learn More

License

This project is private and proprietary.

Releases

Packages

Contributors

Languages