Skip to content

Commit 986d37b

Browse files
authored
Merge pull request #94 from hanzoai/auth/custom-token-auth
Auth: added support for common auth
2 parents 2014fe4 + e1cbd02 commit 986d37b

File tree

7 files changed

+100
-7
lines changed

7 files changed

+100
-7
lines changed

packages/auth/components/auth-widget.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const AuthWidget: React.FC<{
6161
</Button>
6262
) : (
6363
<LinkElement
64-
def={{href: '/login', title: 'Login', variant: 'primary'} satisfies LinkDef}
64+
def={{href: `${process.env.NEXT_PUBLIC_AUTH_ORIGIN}/login`, title: 'Login', variant: 'primary'} satisfies LinkDef}
6565
className='h-8 w-fit !min-w-0'
6666
/>
6767
)

packages/auth/components/login-panel.tsx

+11-5
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const LoginPanel: React.FC<PropsWithChildren & {
4141
className?: string,
4242
inputClx?: string,
4343
noHeading?: boolean
44-
onLoginChanged?: (loggedIn: boolean) => void
44+
onLoginChanged?: (token: string) => void
4545
termsOfServiceUrl?: string
4646
privacyPolicyUrl?: string
4747
}> = observer(({
@@ -61,11 +61,17 @@ const LoginPanel: React.FC<PropsWithChildren & {
6161

6262
const [isLoading, setIsLoading] = useState(false)
6363

64-
const succeed = (loggedOut = false) => {
65-
// If a callback is provide, don't redirect.
66-
// Assume host code is handling (eg, mobile menu)
64+
const succeed = async () => {
65+
// If a callback is provide, don't redirect.
66+
// Assume host code is handling (eg, mobile menu)
6767
if (onLoginChanged) {
68-
onLoginChanged(!loggedOut)
68+
const res = await fetch(
69+
'/api/auth/generate-custom-token',
70+
{ method: 'POST' }
71+
).then(res => res.json())
72+
if (res.success) {
73+
onLoginChanged(res.token.token)
74+
}
6975
}
7076
else if (redirectUrl) {
7177
router.push(redirectUrl)

packages/auth/server/firebase-support.ts

+19
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ async function getSession() {
6969
}
7070
}
7171

72+
export const generateCustomToken = async (): Promise<{success: boolean, token: string | null}> => {
73+
const session = await getSession()
74+
75+
if (!(await isUserAuthenticated(session))) {
76+
return {success: false, token: null}
77+
}
78+
79+
const decodedIdToken = await auth.verifySessionCookie(session!)
80+
const currentUser = await auth.getUser(decodedIdToken.uid)
81+
82+
try {
83+
const token = await auth.createCustomToken(currentUser.uid)
84+
return {success: true, token}
85+
} catch (e) {
86+
console.error('Error generating custom token', e)
87+
return {success: false, token: null}
88+
}
89+
}
90+
7291
export async function createSessionCookie(idToken: string, sessionCookieOptions: SessionCookieOptions) {
7392
return auth.createSessionCookie(idToken, sessionCookieOptions)
7493
}

packages/auth/server/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { getUserServerSide } from './firebase-support'
1+
export { getUserServerSide, generateCustomToken } from './firebase-support'
22
export {
33
handleLogin as handleLoginApiRequest,
44
handleLogout as handleLogoutApiRequest

packages/auth/service/auth-service.ts

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ interface AuthService {
1414
provider: 'google' | 'facebook' | 'github'
1515
) => Promise<{success: boolean, userInfo: HanzoUserInfo | null}>
1616

17+
loginWithCustomToken: (
18+
token: string
19+
) => Promise<{success: boolean, userInfo: HanzoUserInfo | null}>
20+
1721
associateWallet: () => Promise<void>
1822

1923
logout: () => Promise<{success: boolean}>

packages/auth/service/impl/firebase-support.ts

+32
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
createUserWithEmailAndPassword,
88
type User,
99
signInWithEmailAndPassword,
10+
signInWithCustomToken,
1011
} from 'firebase/auth'
1112

1213
import { initializeApp, getApps } from "firebase/app"
@@ -140,6 +141,37 @@ export async function loginWithEmailAndPassword(
140141
}
141142
}
142143

144+
export async function loginWithCustomToken(
145+
token: string,
146+
): Promise<{success: boolean, user?: User }> {
147+
148+
let user: User | undefined = undefined
149+
const userCredential = await signInWithCustomToken(auth, token)
150+
user = userCredential.user
151+
152+
try {
153+
const idToken = await user.getIdToken()
154+
155+
const response = await fetch('/api/auth/login', {
156+
method: 'POST',
157+
headers: { 'Content-Type': 'application/json'},
158+
body: JSON.stringify({ idToken }),
159+
})
160+
const resBody = (await response.json()) as unknown as APIResponse<string>
161+
162+
if (response.ok && resBody.success) {
163+
return { success: true, user }
164+
}
165+
else {
166+
return {success: false}
167+
}
168+
}
169+
catch (error) {
170+
console.error('Error signing in with Firebase auth', error)
171+
return {success: false}
172+
}
173+
}
174+
143175
export async function logoutBackend(): Promise<{success: boolean}> {
144176

145177
try {

packages/auth/service/impl/index.ts

+32
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { AuthServiceConf, HanzoUserInfo, HanzoUserInfoValue } from '../../t
55

66
import {
77
auth as fbAuth,
8+
loginWithCustomToken,
89
loginWithEmailAndPassword,
910
loginWithProvider,
1011
logoutBackend
@@ -133,6 +134,37 @@ class AuthServiceImpl implements AuthService {
133134
}
134135
}
135136

137+
loginWithCustomToken = async (
138+
token: string
139+
): Promise<{success: boolean, userInfo: HanzoUserInfo | null}> => {
140+
141+
try {
142+
this._hzUser.clear()
143+
const res = await loginWithCustomToken(token)
144+
if (res.success && res.user) {
145+
const walletAddress = res.user.email ? await getAssociatedWalletAddress(res.user.email) : undefined
146+
this._hzUser.set({
147+
email: res.user.email ?? '',
148+
displayName : res.user.displayName ?? null,
149+
walletAddress : walletAddress?.result ?? null
150+
})
151+
152+
return {
153+
success: true,
154+
userInfo: this._hzUser
155+
}
156+
}
157+
return {
158+
success: false,
159+
userInfo: null
160+
}
161+
}
162+
catch (e) {
163+
console.error('Error signing in with Firebase auth', e)
164+
return {success: false, userInfo: null}
165+
}
166+
}
167+
136168
associateWallet = async (): Promise<void> => {
137169
if (this._hzUser.isValid) {
138170
const res = await associateWalletAddressWithAccount(this._hzUser.email)

0 commit comments

Comments
 (0)