Skip to content

Commit

Permalink
Move from next-auth to supabase-auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Farina authored and Daniel Farina committed Nov 22, 2023
1 parent c0160c4 commit 8010ff4
Show file tree
Hide file tree
Showing 19 changed files with 379 additions and 594 deletions.
42 changes: 0 additions & 42 deletions docs/docs/configuration/general-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,48 +48,6 @@ SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key

---

### SUPABASE_JWT_SECRET

#### Description

The JWT secret for your Supabase instance. This is a required environment variable.

#### Example

```sh
SUPABASE_JWT_SECRET=your_supabase_jwt_secret
```

---

### NEXTAUTH_SECRET

#### Description

The secret used to encrypt cookies. This is a required environment variable.

#### Example

```sh
NEXTAUTH_SECRET=your_nextauth_secret
```

---

### NEXTAUTH_URL

#### Description

The base url for your app. This is a required environment variable when running in production.

#### Example

```sh
NEXTAUTH_URL=https://yourdomain.com
```

---

### NEXT_PUBLIC_DEFAULT_MODEL

#### Description
Expand Down
48 changes: 12 additions & 36 deletions docs/docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,15 @@ git clone https://github.com/jorge-menjivar/unSAGED.git

## Generate Supabase Tables

Run the [Generation Script](https://github.com/jorge-menjivar/unSAGED/packages/unsaged/db/GenerationScript.sql) in the [Supabase SQL editor](https://app.supabase.com/project/_/sql).
Run the database migration in [Supabase SQL editor](https://app.supabase.com/project/_/sql) or your favorite SQL editor.


This will do the following:

- Create the tables required by unSAGED.
- Create the authentication schema and tables required by Auth.js.
- Enable Row Level Security for the tables required by unSAGED.
- Apply the Row Level Security policies required by unSAGED.

## Expose the `next_auth` schema

Expose the `next_auth` schema in the [API settings](https://app.supabase.com/project/_/settings/api) by adding `next_auth` to the "Exposed schemas" list.

More information [here](https://authjs.dev/reference/adapter/supabase#expose-the-nextauth-schema-in-supabase).

Then copy the output and save it for the next step.

## Switch to the `packages/unsaged` directory

Expand All @@ -42,30 +35,23 @@ cd packages/unsaged
The `.env.local` file is the main configuration file for unSAGED. It should be located in the `packages/unsaged` directory of the project.
Create the `packages/unsaged/.env.local` file to set your environment variables.

### Set Auth Secret

Create your secret with the following command:

```sh
openssl rand -base64 32
```

Set the `NEXTAUTH_SECRET` environment variable to the secret you just created.
### Set Supabase Variables

```sh title="packages/unsaged/.env.local"
NEXTAUTH_SECRET=my_secret
NEXT_PUBLIC_SUPABASE_URL="https://xxxxxxxxxxxxxxxx.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY=supabase_anon_key
```

See [Auth.js Documentation](https://next-auth.js.org/configuration/options#nextauth_secret) for more information.
### Configure your supabase auth providers at

### Set Supabase Variables
https://supabase.com/dashboard/project/xxxxxxxxxxxxxxxx/auth/providers

```sh title="packages/unsaged/.env.local"
NEXT_PUBLIC_SUPABASE_URL="https://xxxxxxxxxxxxxxxx.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY=supabase_anon_key
SUPABASE_JWT_SECRET=supabase_jwt_secret
SUPABASE_SERVICE_ROLE_KEY=supabase_service_role_key
## Enable them or disable them on the UI by adding/removing them from
```
/app/auth/signin/auth-form.tsx
```


## Install Dependencies

Expand All @@ -88,14 +74,4 @@ When running in docker set the following environment variable:
```sh
docker build -t unsaged . --rm
docker run --env-file=.env.local -p 127.0.0.1:3000:3000 --name unsaged unsaged
```

## Running in Production

To run in production, you will need to set the following environment variable.

See [Auth.js Documentation](https://next-auth.js.org/configuration/options#nextauth_url) for more information.

```sh title="packages/unsaged/.env.local"
NEXTAUTH_URL=https://yourdomain.com
```
```
13 changes: 4 additions & 9 deletions packages/unsaged/.env.local.example
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Will print debug messages if true
NEXT_PUBLIC_DEBUG_MODE=false

# Default model
NEXT_PUBLIC_DEFAULT_MODEL="gpt-3.5-turbo"

NEXT_PUBLIC_SITE_URL="http://localhost:3000"
NEXT_PUBLIC_TITLE="unsaged"
NEXT_PUBLIC_DESCRIPTION="Open source chat kit engineered for seamless interaction with AI models"

NEXT_PUBLIC_DEBUG_MODE=true

# OpenAI
OPENAI_API_URL="https://api.openai.com/v1"
OPENAI_API_KEY=openai_key
Expand Down Expand Up @@ -52,19 +56,10 @@ PALM_API_KEY=palm_key
# NEXT_PUBLIC_DEFAULT_PALM_TOP_P=1.0
# NEXT_PUBLIC_DEFAULT_PALM_TOP_K=40

# NextAuth (Required)
NEXTAUTH_EMAIL_PATTERN=
NEXTAUTH_URL="http://localhost:3000"
# You can get secret with `openssl rand -base64 32`
NEXTAUTH_SECRET=nextauth_secret

# At least one provider is required
# Google Auth Provider
GOOGLE_CLIENT_ID="xxxxxxxxxxxxxxxxx.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET=google_client_secret

# Supabase (Required)
NEXT_PUBLIC_SUPABASE_URL="https://xxxxxxxxxxxxxxxx.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY=supabase_anon_key
SUPABASE_JWT_SECRET=supabase_jwt_secret
SUPABASE_SERVICE_ROLE_KEY=supabase_service_role_key
129 changes: 129 additions & 0 deletions packages/unsaged/app/account/account-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
'use client'
import { useCallback, useEffect, useState } from 'react'
import { Database } from '@/types/database'
import { Session, createClientComponentClient } from '@supabase/auth-helpers-nextjs'

export default function AccountForm({ session }: { session: Session | null }) {
const supabase = createClientComponentClient<Database>()
const [loading, setLoading] = useState(true)
const [fullname, setFullname] = useState<string | null>(null)
const [username, setUsername] = useState<string | null>(null)
const [website, setWebsite] = useState<string | null>(null)
const [avatar_url, setAvatarUrl] = useState<string | null>(null)
const user = session?.user

const getProfile = useCallback(async () => {
try {
setLoading(true)

const { data, error, status } = await supabase
.from('profiles')
.select(`full_name, username, website, avatar_url`)
.eq('id', user?.id)
.single()

if (error && status !== 406) {
throw error
}

if (data) {
setFullname(data.full_name)
setUsername(data.username)
setWebsite(data.website)
setAvatarUrl(data.avatar_url)
}
} catch (error) {
alert('Error loading user data!')
} finally {
setLoading(false)
}
}, [user, supabase])

useEffect(() => {
getProfile()
}, [user, getProfile])

async function updateProfile({
username,
website,
avatar_url,
}: {
username: string | null
fullname: string | null
website: string | null
avatar_url: string | null
}) {
try {
setLoading(true)

const { error } = await supabase.from('profiles').upsert({
id: user?.id as string,
full_name: fullname,
username,
website,
avatar_url,
updated_at: new Date().toISOString(),
})
if (error) throw error
alert('Profile updated!')
} catch (error) {
alert('Error updating the data!')
} finally {
setLoading(false)
}
}

return (
<div className="form-widget">
<div>
<label htmlFor="email">Email</label>
<input id="email" type="text" value={session?.user.email} disabled />
</div>
<div>
<label htmlFor="fullName">Full Name</label>
<input
id="fullName"
type="text"
value={fullname || ''}
onChange={(e) => setFullname(e.target.value)}
/>
</div>
<div>
<label htmlFor="username">Username</label>
<input
id="username"
type="text"
value={username || ''}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<label htmlFor="website">Website</label>
<input
id="website"
type="url"
value={website || ''}
onChange={(e) => setWebsite(e.target.value)}
/>
</div>

<div>
<button
className="button primary block"
onClick={() => updateProfile({ fullname, username, website, avatar_url })}
disabled={loading}
>
{loading ? 'Loading ...' : 'Update'}
</button>
</div>

<div>
<form action="/auth/signout" method="post">
<button className="button block" type="submit">
Sign out
</button>
</form>
</div>
</div>
)
}
14 changes: 14 additions & 0 deletions packages/unsaged/app/account/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { Database } from '@/types/database'
import AccountForm from './account-form'

export default async function Account() {
const supabase = createServerComponentClient<Database>({ cookies })

const {
data: { session },
} = await supabase.auth.getSession()

return <AccountForm session={session} />
}
44 changes: 0 additions & 44 deletions packages/unsaged/app/api/auth/[...nextauth]/route.ts

This file was deleted.

18 changes: 18 additions & 0 deletions packages/unsaged/app/api/auth/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

import type { Database } from '@/types/database'

export async function GET(request: Request) {
const requestUrl = new URL(request.url)
const code = requestUrl.searchParams.get('code')

if (code) {
const supabase = createRouteHandlerClient<Database>({ cookies })
await supabase.auth.exchangeCodeForSession(code)
}

// URL to redirect to after sign in process completes
return NextResponse.redirect(requestUrl.origin)
}
16 changes: 16 additions & 0 deletions packages/unsaged/app/auth/callback/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest) {
const cookieStore = cookies()
const supabase = createRouteHandlerClient({ cookies: () => cookieStore })
const { searchParams } = new URL(req.url)
const code = searchParams.get('code')

if (code) {
await supabase.auth.exchangeCodeForSession(code)
}

return NextResponse.redirect(new URL('/', req.url))
}
Loading

0 comments on commit 8010ff4

Please sign in to comment.