Skip to content

Commit

Permalink
fix: withAuthRequired for API routes. (#27)
Browse files Browse the repository at this point in the history
* fix: remove onUserLoaded mechanism.

* fix: withAuthRequired for API routes.
  • Loading branch information
thorwebdev authored Feb 22, 2022
1 parent 242b7d1 commit 2725584
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 176 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 1.1.2 - 2022-02-22

- Makes `withAuthRequired` work for API routes as well. See [the docs](./src/nextjs/README.md#protecting-api-routes) for more details.
- Removes `onUserLoaded` prop as it was rather confusing and user might want to choose other ways to manage their user state rather than React context.

## 1.1.1 - 2022-02-22

- [#24](https://github.com/supabase-community/supabase-auth-helpers/pull/24): feat: onUserLoaded prop in UserProvider:
Expand Down
16 changes: 2 additions & 14 deletions examples/nextjs/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import '../styles/globals.css';
import type { AppProps } from 'next/app';
import { UserProvider } from '@supabase/supabase-auth-helpers/react';
import {
supabaseClient,
SupabaseClient
} from '@supabase/supabase-auth-helpers/nextjs';
import { supabaseClient } from '@supabase/supabase-auth-helpers/nextjs';

// You can pass an onUserLoaded method to fetch additional data from your public scema.
// This data will be available as the `onUserLoadedData` prop in the `useUser` hook.
function MyApp({ Component, pageProps }: AppProps) {
return (
<UserProvider
supabaseClient={supabaseClient}
onUserLoaded={async (supabaseClient) => {
// Since supabase is so fast, we need a 2s sleep here to test that it's working :D
await new Promise((r) => setTimeout(r, 2000));
return (await supabaseClient.from('test').select('*').single()).data;
}}
>
<UserProvider supabaseClient={supabaseClient}>
<Component {...pageProps} />
</UserProvider>
);
Expand Down
13 changes: 0 additions & 13 deletions examples/nextjs/pages/api/hello.ts

This file was deleted.

13 changes: 13 additions & 0 deletions examples/nextjs/pages/api/protected-route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// pages/api/protected-route.ts
import {
withAuthRequired,
supabaseServerClient
} from '@supabase/supabase-auth-helpers/nextjs';

export default withAuthRequired(async function ProtectedRoute(req, res) {
// Run queries with RLS on the server
const { data } = await supabaseServerClient({ req, res })
.from('test')
.select('*');
res.json(data);
});
15 changes: 13 additions & 2 deletions examples/nextjs/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ import { useUser, Auth } from '@supabase/supabase-auth-helpers/react';
import { supabaseClient } from '@supabase/supabase-auth-helpers/nextjs';
import type { NextPage } from 'next';
import Link from 'next/link';
import { useEffect, useState } from 'react';

const LoginPage: NextPage = () => {
const { isLoading, user, onUserLoadedData, error } = useUser();
const { isLoading, user, error } = useUser();
const [data, setData] = useState(null);

useEffect(() => {
async function loadData() {
const { data } = await supabaseClient.from('test').select('*').single();
setData(data);
}
if (user) loadData();
}, [user]);

if (!user)
return (
<>
{error && <p>{error.message}</p>}
{isLoading ? <h1>Loading...</h1> : <h1>Loaded!</h1>}
<Auth
// view="update_password"
supabaseClient={supabaseClient}
Expand All @@ -31,7 +42,7 @@ const LoginPage: NextPage = () => {
<p>user:</p>
<pre>{JSON.stringify(user, null, 2)}</pre>
<p>client-side data fetching with RLS</p>
<pre>{JSON.stringify(onUserLoadedData, null, 2)}</pre>
<pre>{JSON.stringify(data, null, 2)}</pre>
</>
);
};
Expand Down
3 changes: 0 additions & 3 deletions examples/nextjs/pages/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// pages/profile.js
import { withAuthRequired, User } from '@supabase/supabase-auth-helpers/nextjs';
import { useUser } from '@supabase/supabase-auth-helpers/react';
import Link from 'next/link';

export default function Profile({ user }: { user: User }) {
const { onUserLoadedData } = useUser();
return (
<>
<p>
Expand All @@ -13,7 +11,6 @@ export default function Profile({ user }: { user: User }) {
</p>
<div>Hello {user.email}</div>
<pre>{JSON.stringify(user, null, 2)}</pre>
<pre>{JSON.stringify(onUserLoadedData, null, 2)}</pre>
</>
);
}
Expand Down
55 changes: 23 additions & 32 deletions src/nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,38 +67,6 @@ export default function App({ Component, pageProps }) {

You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined.

## Loading additional user data

The `user` object from the `useUser()` hook is only meant to be used as an indicator that the user is signed in, you're not meant to store additional user information in this object but rather you're meant to store additional information in your `public.users` table. See [the "Managing User Data" docs](https://supabase.com/docs/guides/auth/managing-user-data) for more details on this.

You can conveniently make your additional user data available in the `useUser()` hook but setting the `onUserDataLoaded` prop on the `UserProvider` components:

```js
import type { AppProps } from 'next/app';
import { UserProvider } from '@supabase/supabase-auth-helpers/react';
import {
supabaseClient,
SupabaseClient
} from '@supabase/supabase-auth-helpers/nextjs';

// You can pass an onUserLoaded method to fetch additional data from your public schema.
// This data will be available as the `onUserLoadedData` prop in the `useUser` hook.
function MyApp({ Component, pageProps }: AppProps) {
return (
<UserProvider
supabaseClient={supabaseClient}
onUserLoaded={async (supabaseClient) =>
(await supabaseClient.from('users').select('*').single()).data
}
>
<Component {...pageProps} />
</UserProvider>
);
}

export default MyApp;
```

## Client-side data fetching with RLS

For [row level security](https://supabase.com/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to import the `{ supabaseClient }` from `# @supabase/supabase-auth-helpers/nextjs` and only run your query once the user is defined client-side in the `useUser()` hook:
Expand Down Expand Up @@ -222,3 +190,26 @@ export const getServerSideProps = withAuthRequired({
}
});
```

## Protecting API routes

Wrap an API Route to check that the user has a valid session. If they're not logged in the handler will return a
401 Unauthorized.

```js
// pages/api/protected-route.js
import {
withAuthRequired,
supabaseServerClient
} from '@supabase/supabase-auth-helpers/nextjs';

export default withAuthRequired(async function ProtectedRoute(req, res) {
// Run queries with RLS on the server
const { data } = await supabaseServerClient({ req, res })
.from('test')
.select('*');
res.json(data);
});
```

If you visit `/api/protected-route` without a valid session cookie, you will get a 401 response.
Loading

0 comments on commit 2725584

Please sign in to comment.