Firstly I am a Full Stack Bootcamp Graduate and just trying to get my head into NextJS, so this might be newbie questions here.
Now I am using a NextJS TypeScript template and using Supabase for Authentification:
- Using Supabase, I want to store the signup (during/after user creation) formdata (especially userrole & callsign, but also firstname und lastname) directly to the db in the users table and not in the session or raw_user_meta_data. Is this possible via supabase? I have already added two new columns to the auth.users table in via SQL editor in the supabase account. So once a user signs up the first time, his form data should be stored in the auth.user table.
Some code here:
sign-up-form.tsx
import ....
const schema = zod.object({
firstname: zod.string().min(3, { message: 'First name is required' }),
lastname: zod.string().min(3, { message: 'Last name is required' }),
email: zod.string().min(3, { message: 'Email is required' }).email(),
callsign: zod.string().min(3, { message: 'CallSign is required' }),
userrole: zod.string().min(3, { message: 'Userrole is required' }),
password: zod.string().min(6, { message: 'Password should be at least 6 characters' }),
terms: zod.boolean().refine((value) => value, 'You must accept the terms and conditions'),
});
const onSubmit = React.useCallback(
async (values: Values): Promise<void> => {
setIsPending(true);
const redirectToUrl = new URL(paths.auth.supabase.callback.pkce, window.location.origin);
redirectToUrl.searchParams.set('next', paths.dashboard.overview);
const defaultValues = { firstname: '', lastname: '', email: '', callsign:'', userrole: '', password: '', terms: false } satisfies Values;
const { data, error } = await supabaseClient.auth.signUp({
// firstName: values.firstName, // VS code error msg "Object literal may only specify known properties, and 'firstName' does not exist in type SignUpWithPasswordCredentials'.",
// lastName: values.lastName, // VS code error here too
email: values.email,
password: values.password,
options: {
data: {
callsign: values.callsign, // this will be available in raw_metadata but I directly want to save it to the db in auth.users
userrole: values.userrole, //save this in the db too
},
emailRedirectTo: redirectToUrl.href,
},
});
if (error) {
setError('root', { type: 'server', message: error.message });
setIsPending(false);
return;
}
if (data.session) {
return;
}
if (data.user) {
const searchParams = new URLSearchParams({ email: values.email });
router.push(`${paths.auth.supabase.signUpConfirm}?${searchParams.toString()}`);
return;
}
setIsPending(false);
},
[supabaseClient, router, setError]
);
return(
Form....
......
signUp function (GoTrueClients.ts)
async signUp(credentials: SignUpWithPasswordCredentials): Promise<AuthResponse> {
try {
await this._removeSession()
let res: AuthResponse
if ('email' in credentials) {
const { email, password, options } = credentials
let codeChallenge: string | null = null
let codeChallengeMethod: string | null = null
if (this.flowType === 'pkce') {
const codeVerifier = generatePKCEVerifier()
await setItemAsync(this.storage, `${this.storageKey}-code-verifier`, codeVerifier)
codeChallenge = await generatePKCEChallenge(codeVerifier)
codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
}
res = await _request(this.fetch, 'POST', `${this.url}/signup`, {
headers: this.headers,
redirectTo: options?.emailRedirectTo,
body: {
email,
password,
data: options?.data ?? {},
gotrue_meta_security: { captcha_token: options?.captchaToken },
code_challenge: codeChallenge,
code_challenge_method: codeChallengeMethod,
},
xform: _sessionResponse,
})
} else if ('phone' in credentials) {
const { phone, password, options } = credentials
res = await _request(this.fetch, 'POST', `${this.url}/signup`, {
headers: this.headers,
body: {
phone,
password,
data: options?.data ?? {},
channel: options?.channel ?? 'sms',
gotrue_meta_security: { captcha_token: options?.captchaToken },
},
xform: _sessionResponse,
})
} else {
throw new AuthInvalidCredentialsError(
'You must provide either an email or phone number and a password'
)
}
const { data, error } = res
if (error || !data) {
return { data: { user: null, session: null }, error: error }
}
const session: Session | null = data.session
const user: User | null = data.user
if (data.session) {
await this._saveSession(data.session)
await this._notifyAllSubscribers('SIGNED_IN', session)
}
return { data: { user, session }, error: null }
} catch (error) {
if (isAuthError(error)) {
return { data: { user: null, session: null }, error }
}
throw error
}
}
middleware.tsx:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { config as appConfig } from '@/config';
import { AuthStrategy } from '@/lib/auth/strategy';
import { supabaseMiddleware } from '@/lib/auth/supabase/middleware';
export async function middleware(req: NextRequest): Promise<NextResponse> {
let res: NextResponse;
if (appConfig.auth.strategy === AuthStrategy.SUPABASE) {
res = await supabaseMiddleware(req);
} else {
res = NextResponse.next({ headers: req.headers });
}
return res;
}
export const config = { matcher: ['/auth/:path*', '/dashboard/:path*'] };
2. After a login I want to fetch the userrole from db from auth.users to then conditional render multiple dashboards depending on the fetched userrole from auth.users.
According to the supabase docu (https://supabase.com/docs/reference/javascript/select) this should work:
const { data, error } = await supabase
.from('countries')
.select()
but it doesn’t as modules and other functions are missing.
Sorry…quite junior noob questions I guess. Thanks already
Just mentioned above what I tried and pasted some code snippets.
Maybe you have some recommendations of additional documentation or example github repos that i can look into?
What am I missing?