This starter configures NextAuth with Cognito and support usage of Supabase Row Level Security. Users sessions are created on Supabase using Supabase Database Adaptator
- Next.js App router
- supabase-js. Supabase's isomorphic JavaScript library.
- NextAuth offers authentication with cognito, making the user's session available throughout the entire Next.js app, for both client and server.
- NextAuth Supabase Adapter insert/updapte/delete the user session in supabase.
- AWS Cognito with an active user pool
npm install
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
SUPABASE_JWT_SECRET=
can be found in your Supabase project's API settings
NEXT_PUBLIC_COGNITO_CALLBACK_URL=
COGNITO_CLIENT_ID=
COGNITO_CLIENT_SECRET=
COGNITO_ISSUER=https://cognito-idp.{region}.amazonaws.com/{poolID}
see point 4 for configuration.
To configure NextAuth Supabase Adapter with Supabase, please follow the steps describe here. You'll have to make sure you create the new NextAuth schema.
- Create a user pool on AWS Cognito with the default settings.
- Once its done, go to App-in-Integration and Add new App client
- Create a Public Client. Allow client secret generation. Add a callback url. (Make sure this callback url is exactly the same as variable NEXT_PUBLIC_COGNITO_CALLBACK_URL)
- Get the Client ID and Client secret under the App Client Information, Add it to to your .env.local (COGNITO_CLIENT_ID, COGNITO_CLIENT_SECRET)
- Get the Region and Pool ID. User PoolID should be find under `User Pool Overview` and region under Cognito domain. (For ex: .ap-southeast-2). Add it to your .env.local (COGNITO_ISSUER)
# An example of Cognito issuer.
COGNITO_ISSUER=https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-2_V9v4hV0sw
npm run dev
The starter kit should now be running on localhost:3000.
Check out the docs for Local Development to also run Supabase locally.
In order to benefit from the Row Level Security feature in Supabase, make sure to provide the JWT token in the headers upon client instance creation.
import { authConfig } from '@/lib/auth'
import { getServerSession } from 'next/auth'
import { createClient } from '@supabase/supabase-js'
async function getUser() {
const session = await getServerSession(authConfig)
const supabaseAccessToken = session?.supabaseAccessToken
if (!supabaseAccessToken) {
return null
}
const supabase =
createClient <
Database >
(process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
global: {
headers: { Authorization: `Bearer ${supabaseAccessToken}` },
},
})
const { data, error } = await supabase.from('users').select('*').single()
if (error) return null
return data
}
Note that column encryption should only be used in highly sensitive scenarios as it has a meaningful impact on statement performance and flexibility. Supabase projects are already encrypted at rest by default.
Go to Supabase Dashboard -> Project Settings -> Vault -> Encryption key -> Add new key -> Copy your ID.
Add a column with the data type 'text' where encryption is needed.
RUN SQL command to use encryption on this column using you encryption key id.
SECURITY LABEL FOR pgsodium ON COLUMN public.todos.content
IS 'ENCRYPT WITH KEY ID c0b1ca7c-8023-4136-a13e-ea1aa7602178';
This will create a view decrypted_todos, so you can read decrypted data from it. You'll have to allow RLS to work, as views do not enforce RLS by default.
You'll have to drop the table and add WITH (security_invoker = true)
to the query.
DROP VIEW IF EXISTS public.decrypted_todos;
create view
public.decrypted_todos as
select
todos.id,
todos.created_at,
todos.content,
case
when todos.content is null then null::text
else case
when 'c0b1ca7c-8023-4136-a13e-ea1aa7602178' is null then null::text
else convert_from(
pgsodium.crypto_aead_det_decrypt (
decode(todos.content, 'base64'::text),
convert_to(''::text, 'utf8'::name),
'c0b1ca7c-8023-4136-a13e-ea1aa7602178'::uuid,
null::bytea
),
'utf8'::name
)
end
end as decrypted_content,
todos.user_id
from
todos;
Finally, Allow using pgsodium.crypto_aead_det_decrypt for authenticated roles
GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_decrypt (bytea, bytea, uuid, bytea) TO authenticated;
GRANT EXECUTE ON FUNCTION pgsodium.crypto_aead_det_encrypt (bytea, bytea, uuid, bytea) TO authenticated;