# BetterAuth Last.fm Plugin

A clean, modern Last.fm authentication plugin for [BetterAuth](https://better-auth.com).

## Features

- 🔐 Complete Last.fm authentication flow implementation
- 🎵 Session key storage for Last.fm API calls
- 🌟 TypeScript support with full type safety
- 🛠️ Modern architecture following BetterAuth patterns
- 🚀 Zero additional dependencies (except peer dependencies)

## Installation

```bash
npm install @ley0x/better-auth-lastfm
# or
pnpm add @ley0x/better-auth-lastfm
# or
yarn add @ley0x/better-auth-lastfm
```

## Setup

### 1. Get Last.fm API Credentials

1. Visit [Last.fm API Account Creation](https://www.last.fm/api/account/create)
2. Create an application to get your API Key and Shared Secret

### 2. Server Configuration

```typescript
import { betterAuth } from 'better-auth'
import { lastfmPlugin } from '@ley0x/better-auth-lastfm'

export const auth = betterAuth({
  // ... your other config
  plugins: [
    lastfmPlugin({
      apiKey: process.env.LASTFM_API_KEY!,
      sharedSecret: process.env.LASTFM_SHARED_SECRET!,
      // Optional: customize redirect URL after successful auth
      redirectTo: '/dashboard', // default: '/dashboard'
      // Optional: set base URL (usually auto-detected)
      baseUrl: process.env.BETTER_AUTH_URL,
    }),
  ],
  // Optional: customize session expiration (default: 7 days)
  session: {
    expiresIn: 60 * 60 * 24 * 30, // 30 days
    updateAge: 60 * 60 * 24, // Update session every day
  },
})
```

### 3. Client Configuration

```typescript
import { createAuthClient } from 'better-auth/react'
import { lastfmClientPlugin } from '@ley0x/better-auth-lastfm/client'

export const authClient = createAuthClient({
  plugins: [lastfmClientPlugin()],
})

export const { useSession, signOut, signIn, signUp } = authClient
```

## Usage

### Basic Sign-In

```typescript
import { authClient } from './auth-client'

// Redirect to Last.fm authentication
await authClient.signInWithLastfm()
```

### React Component Example

```typescript
import { authClient } from './auth-client'

function LoginButton() {
  const handleSignIn = async () => {
    await authClient.signInWithLastfm()
  }

  return (
    <button onClick={handleSignIn}>
      Sign in with Last.fm
    </button>
  )
}
```

### Getting Last.fm Session Key

After authentication, you can retrieve the Last.fm session key to make API calls:

```typescript
import { authClient } from './auth-client'

// Get the Last.fm session key for API calls
const sessionKey = await authClient.getLastfmSessionKey()

if (sessionKey) {
  // Use session key to call Last.fm API
  // Example: get user's recent tracks, scrobble, etc.
}
```

### Making Last.fm API Calls

```typescript
import { createLastfmApiSignature } from '@ley0x/better-auth-lastfm'

async function getRecentTracks(username: string, sessionKey: string) {
  const params = {
    method: 'user.getRecentTracks',
    user: username,
    api_key: process.env.LASTFM_API_KEY!,
    sk: sessionKey,
    format: 'json',
  }

  const signature = createLastfmApiSignature(params, process.env.LASTFM_SHARED_SECRET!)

  const url = new URL('https://ws.audioscrobbler.com/2.0/')
  Object.entries({ ...params, api_sig: signature }).forEach(([key, value]) => {
    url.searchParams.set(key, value)
  })

  const response = await fetch(url)
  return response.json()
}
```

## Environment Variables

Add these to your `.env` file:

```env
LASTFM_API_KEY=your_api_key_here
LASTFM_SHARED_SECRET=your_shared_secret_here
BETTER_AUTH_URL=http://localhost:3000  # Your app's base URL
BETTER_AUTH_SECRET=your_secret_here    # BetterAuth secret
```

## Database Schema

The plugin uses BetterAuth's standard user and account tables. Last.fm session keys are stored in the `accessToken` field of the account record.

## Session Configuration

By default, BetterAuth sessions expire after 7 days. You can customize the session expiration by adding a `session` configuration object to your `betterAuth` configuration:

```typescript
export const auth = betterAuth({
  plugins: [
    lastfmPlugin({
      /* ... */
    }),
  ],
  session: {
    expiresIn: 60 * 60 * 24 * 30, // 30 days (default: 7 days)
    updateAge: 60 * 60 * 24, // Update session every day (default: 1 day)
  },
})
```

### Important: Session Persistence Fix

**Note**: A recent fix ensures sessions persist across browser restarts. The plugin now properly respects cookie `maxAge` settings. See [SESSION_PERSISTENCE_SOLUTION.md](SESSION_PERSISTENCE_SOLUTION.md) for details.

### Recommended Configuration for Persistence

```typescript
export const auth = betterAuth({
  plugins: [
    lastfmPlugin({
      /* ... */
    }),
  ],
  session: {
    expiresIn: 60 * 60 * 24 * 30, // 30 days
    updateAge: 60 * 60 * 24,
    cookieCache: {
      enabled: true,
      maxAge: 60 * 60 * 24,
      strategy: 'compact',
    },
  },
  cookies: {
    sessionToken: {
      attributes: {
        maxAge: 60 * 60 * 24 * 30, // Persistent cookie
      },
    },
  },
})
```

## API Reference

### `lastfmPlugin(options)`

Server-side plugin configuration.

#### Options

- `apiKey` (required): Your Last.fm API key
- `sharedSecret` (required): Your Last.fm shared secret
- `baseUrl` (optional): Your app's base URL for callbacks
- `redirectTo` (optional): Path to redirect after successful auth

### `lastfmClientPlugin()`

Client-side plugin for browser environments.

### Client Methods

- `signInWithLastfm()`: Initiates Last.fm authentication flow
- `getLastfmSessionKey()`: Returns the user's Last.fm session key

## TypeScript Support

Full TypeScript support with exported types:

```typescript
import type {
  LastfmPluginOptions,
  LastfmSession,
  LastfmAuthResponse,
  LastfmUserProfile,
} from '@ley0x/better-auth-lastfm'
```

## Contributing

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

## License

MIT
