npm package: @seneris/nextauth-moopy-provider
Description: Moopy OAuth provider for NextAuth.js
Author: Seneris BV
Latest version: 1.0.0

# @seneris/nextauth-moopy-provider

Moopy OAuth provider for [NextAuth.js](https://next-auth.js.org/).

## Features

- 🔐 OAuth 2.0 authentication with Moopy
- 🔒 PKCE support for enhanced security
- 📦 TypeScript support with full type definitions
- 🎨 Custom Moopy branding
- 🔧 Support for Moopy-specific profile fields (subscription tier, authorized apps, preferences)
- ✅ Type augmentation for Next-Auth session and JWT

## Installation

```bash
npm install @seneris/nextauth-moopy-provider next-auth
# or
yarn add @seneris/nextauth-moopy-provider next-auth
# or
pnpm add @seneris/nextauth-moopy-provider next-auth
```

## Prerequisites

1. Register your application in the Moopy OAuth system
2. Obtain your Client ID and Client Secret
3. Configure redirect URIs:
   - Development: `http://localhost:3000/api/auth/callback/moopy`
   - Production: `https://yourdomain.com/api/auth/callback/moopy`

## Usage

### Basic Setup

```typescript
import NextAuth, { NextAuthOptions } from "next-auth"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import MoopyProvider from "@seneris/nextauth-moopy-provider"
import { prisma } from "@/lib/prisma"

export const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma),
  providers: [
    MoopyProvider({
      clientId: process.env.MOOPY_CLIENT_ID!,
      clientSecret: process.env.MOOPY_CLIENT_SECRET!,
      issuer: process.env.MOOPY_ISSUER_URL || 'https://moopy.nl',
    }),
  ],
  session: {
    strategy: "jwt"
  },
  callbacks: {
    async session({ session, token }) {
      if (token && session.user) {
        session.user.id = token.sub as string
        // Moopy-specific fields are automatically included
        session.user.subscription_tier = token.subscription_tier
        session.user.subscription_status = token.subscription_status
      }
      return session
    },
    async jwt({ token, user, account }) {
      if (user && account?.provider === 'moopy') {
        token.subscription_tier = user.subscription_tier
        token.subscription_status = user.subscription_status
        token.authorized_apps = user.authorized_apps
        token.preferences = user.preferences
      }
      return token
    },
  }
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
```

### Environment Variables

Add to your `.env` file:

```bash
MOOPY_CLIENT_ID=your-client-id-here
MOOPY_CLIENT_SECRET=your-client-secret-here
MOOPY_ISSUER_URL=https://moopy.nl

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=generate-with-openssl-rand-base64-32
```

### Custom Configuration

You can customize the OAuth scopes and other settings:

```typescript
import { createMoopyProvider } from "@seneris/nextauth-moopy-provider"

const provider = createMoopyProvider({
  clientId: process.env.MOOPY_CLIENT_ID!,
  clientSecret: process.env.MOOPY_CLIENT_SECRET!,
  issuer: 'https://moopy.nl',
  scope: 'email profile custom-scope'
})
```

## Moopy Profile Fields

The provider includes these Moopy-specific profile fields:

```typescript
interface MoopyProfile {
  sub: string                    // User ID
  email?: string                 // Email address
  email_verified?: boolean       // Email verification status
  name?: string                  // Full name
  given_name?: string           // First name
  family_name?: string          // Last name
  picture?: string              // Profile picture URL
  updated_at?: number           // Last update timestamp
  subscription_tier?: string    // Subscription level (free, pro, enterprise)
  subscription_status?: string  // Status (active, cancelled, expired)
  authorized_apps?: Array<{     // Other apps user has authorized
    client_id: string
    name: string
  }>
  preferences?: Record<string, unknown>  // User preferences
}
```

## TypeScript

The package includes full TypeScript support and automatically augments Next-Auth types to include Moopy-specific fields.

### Accessing Moopy Fields

In your components:

```typescript
import { useSession } from "next-auth/react"

export function MyComponent() {
  const { data: session } = useSession()

  // TypeScript knows about Moopy fields
  const tier = session?.user?.subscription_tier
  const status = session?.user?.subscription_status

  return (
    <div>
      <p>Subscription: {tier}</p>
      <p>Status: {status}</p>
    </div>
  )
}
```

In API routes:

```typescript
import { getServerSession } from "next-auth"
import { authOptions } from "@/lib/auth"

export async function GET() {
  const session = await getServerSession(authOptions)

  if (!session) {
    return new Response("Unauthorized", { status: 401 })
  }

  // Access Moopy fields
  const tier = session.user.subscription_tier

  return Response.json({ tier })
}
```

## Security

- Uses PKCE (Proof Key for Code Exchange) for enhanced security
- Supports state and nonce checks
- Follows OAuth 2.0 best practices
- Always use HTTPS in production

## Examples

### Sign In Button

```typescript
"use client"

import { signIn } from "next-auth/react"
import { Button } from "@/components/ui/button"

export function SignInButton() {
  return (
    <Button onClick={() => signIn("moopy")}>
      Sign in with Moopy
    </Button>
  )
}
```

### Protected API Route

```typescript
import { NextRequest, NextResponse } from "next/server"
import { getServerSession } from "next-auth"
import { authOptions } from "@/lib/auth"

export async function GET(request: NextRequest) {
  const session = await getServerSession(authOptions)

  if (!session?.user?.id) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
  }

  return NextResponse.json({
    userId: session.user.id,
    tier: session.user.subscription_tier
  })
}
```

## Troubleshooting

### Redirect URI Mismatch

Ensure your redirect URI in the Moopy OAuth app exactly matches:
```
http://localhost:3000/api/auth/callback/moopy
```

### Session Not Persisting

- Verify `NEXTAUTH_SECRET` is set
- Check `NEXTAUTH_URL` matches your domain
- Ensure cookies are enabled in browser

### Custom Fields Not Available

Make sure you include the callbacks in your auth configuration to pass Moopy fields from the JWT to the session (see Usage example above).

## License

MIT

## Contributing

Contributions are welcome! Please open an issue or submit a pull request.

## Support

For issues related to:
- **This provider:** [GitHub Issues](https://github.com/seneris/nextauth-moopy-provider/issues)
- **NextAuth.js:** [NextAuth.js Documentation](https://next-auth.js.org)
- **Moopy OAuth:** Contact Moopy support

## Links

- [NextAuth.js Documentation](https://next-auth.js.org)
- [OAuth 2.0 Specification](https://oauth.net/2/)
- [Moopy](https://moopy.nl)