Skip to content

Commit

Permalink
Auth: Custom getCurrentUser
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed Jul 22, 2022
1 parent 5b552a2 commit c175b8e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 11 deletions.
26 changes: 22 additions & 4 deletions packages/auth/src/AuthProvider/AuthProvider.tsx
Expand Up @@ -2,7 +2,7 @@ import React, { ReactNode, useState } from 'react'

import { AuthImplementation } from 'src/authImplementations/AuthImplementation'

import { AuthContextInterface } from '../AuthContext'
import { AuthContextInterface, CurrentUser } from '../AuthContext'

import {
AuthProviderState,
Expand Down Expand Up @@ -72,7 +72,13 @@ export function createAuthProvider<
TResetPassword,
TValidateResetToken,
TVerifyOtp
>
>,
customProviderHooks?: {
useCurrentUser?: () => Promise<Record<string, unknown>>
useHasRole?: (
currentUser: CurrentUser | null
) => (rolesToCheck: string | string[]) => boolean
}
) {
/**
* @example
Expand Down Expand Up @@ -117,13 +123,25 @@ export function createAuthProvider<
* missed or slip through.
*/
const getToken = useToken(authImplementation)
const getCurrentUser = useCurrentUser(authImplementation)

// We're disabling eslint here, because while yes, technically we are
// conditionally calling a hook, which you're not allowed to do. But in
// practice a customProviderHook is either always going to be supplied,
// or never
const getCurrentUser = customProviderHooks?.useCurrentUser
? customProviderHooks.useCurrentUser
: // eslint-disable-next-line react-hooks/rules-of-hooks
useCurrentUser(authImplementation)
const reauthenticate = useReauthenticate(
authImplementation,
setAuthProviderState,
skipFetchCurrentUser
)
const hasRole = useHasRole(authProviderState.currentUser)

const hasRole = customProviderHooks?.useHasRole
? customProviderHooks.useHasRole(authProviderState.currentUser)
: // eslint-disable-next-line react-hooks/rules-of-hooks
useHasRole(authProviderState.currentUser)
const signUp = useSignUp(
authImplementation,
setAuthProviderState,
Expand Down
16 changes: 13 additions & 3 deletions packages/auth/src/authFactory.ts
@@ -1,4 +1,4 @@
import { createAuthContext } from './AuthContext'
import { createAuthContext, CurrentUser } from './AuthContext'
import { AuthImplementation } from './authImplementations/AuthImplementation'
import { createAuthProvider } from './AuthProvider/AuthProvider'
import { createUseAuth } from './useAuth'
Expand All @@ -24,7 +24,13 @@ export function createAuthentication<
TResetPassword,
TValidateResetToken,
TVerifyOtp
>
>,
customProviderHooks?: {
useCurrentUser?: () => Promise<Record<string, unknown>>
useHasRole?: (
currentUser: CurrentUser | null
) => (rolesToCheck: string | string[]) => boolean
}
) {
const AuthContext = createAuthContext<
TUser,
Expand All @@ -36,7 +42,11 @@ export function createAuthentication<
TValidateResetToken
>()
const useAuth = createUseAuth(AuthContext)
const AuthProvider = createAuthProvider(AuthContext, authImplementation)
const AuthProvider = createAuthProvider(
AuthContext,
authImplementation,
customProviderHooks
)

// TODO: Do we really need to return AuthContext here?
return { AuthContext, AuthProvider, useAuth }
Expand Down
13 changes: 11 additions & 2 deletions packages/auth/src/authImplementations/netlify.ts
Expand Up @@ -2,6 +2,7 @@ import type * as NetlifyIdentityNS from 'netlify-identity-widget'

import { isBrowser } from '@redwoodjs/prerender/browserUtils'

import { CurrentUser } from 'src/AuthContext'
import { createAuthentication } from 'src/authFactory'
// TODO:
// In the future, when this is a separate package, we can import the full thing
Expand All @@ -13,7 +14,15 @@ import { AuthImplementation } from './AuthImplementation'

type NetlifyIdentity = typeof NetlifyIdentityNS

export function createNetlifyAuth(netlifyIdentity: NetlifyIdentity) {
export function createNetlifyAuth(
netlifyIdentity: NetlifyIdentity,
customProviderHooks?: {
useCurrentUser?: () => Promise<Record<string, unknown>>
useHasRole?: (
currentUser: CurrentUser | null
) => (rolesToCheck: string | string[]) => boolean
}
) {
const authImplementation = createNetlifyAuthImplementation(netlifyIdentity)

isBrowser && netlifyIdentity.init()
Expand All @@ -28,7 +37,7 @@ export function createNetlifyAuth(netlifyIdentity: NetlifyIdentity) {
never,
never,
never
>(authImplementation)
>(authImplementation, customProviderHooks)
}

function createNetlifyAuthImplementation(
Expand Down
25 changes: 23 additions & 2 deletions packages/auth/src/authImplementations/supabase.ts
Expand Up @@ -5,6 +5,9 @@ import type {
GoTrueClient,
} from '@supabase/supabase-js'

import { CurrentUser } from 'src/AuthContext'
import { createAuthentication } from 'src/authFactory'

import { AuthImplementation } from './AuthImplementation'

type SignInOptions = {
Expand All @@ -30,10 +33,28 @@ type VerifyOtpOptions = {
redirectTo?: string
}

export function createSupabaseAuth(supabaseClient: SupabaseClient) {
export function createSupabaseAuth(
supabaseClient: SupabaseClient,
customProviderHooks?: {
useCurrentUser?: () => Promise<Record<string, unknown>>
useHasRole?: (
currentUser: CurrentUser | null
) => (rolesToCheck: string | string[]) => boolean
}
) {
const authImplementation = createSupabaseAuthImplementation(supabaseClient)

return authImplementation
return createAuthentication<
User,
void,
Awaited<ReturnType<GoTrueClient['signIn']>>,
Awaited<ReturnType<GoTrueClient['signOut']>>,
Awaited<ReturnType<GoTrueClient['signUp']>>,
never,
never,
never,
Awaited<ReturnType<GoTrueClient['verifyOTP']>>
>(authImplementation, customProviderHooks)
}

function createSupabaseAuthImplementation(
Expand Down

0 comments on commit c175b8e

Please sign in to comment.