Skip to content

Commit

Permalink
Use native email login support
Browse files Browse the repository at this point in the history
  • Loading branch information
Agusx1211 committed Nov 8, 2023
1 parent 93c2341 commit 7892675
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 262 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
"@0xsequence/design-system": "^1.0.13",
"@0xsequence/indexer": "^1.1.3",
"@0xsequence/network": "^1.1.3",
"@0xsequence/waas": "0.0.0-20231108135717",
"@aws-sdk/client-cognito-identity-provider": "^3.441.0",
"@0xsequence/waas": "0.0.0-20231108174744",
"@react-oauth/google": "^0.11.1",
"@vanilla-extract/css": "^1.12.0",
"axios": "^1.6.0",
Expand Down
173 changes: 10 additions & 163 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const node = new ethers.providers.JsonRpcProvider('https://nodes.sequence

export const sequence = new Sequence({
network: 'polygon',
key: 'eyJzZWNyZXQiOiJ0YmQiLCJ0ZW5hbnQiOjksImlkZW50aXR5UG9vbElkIjoidXMtZWFzdC0yOjQyYzlmMzlkLWM5MzUtNGQ1Yy1hODQ1LTVjODgxNWM3OWVlMyJ9',
key: 'eyJzZWNyZXQiOiJ0YmQiLCJ0ZW5hbnQiOjksImlkZW50aXR5UG9vbElkIjoidXMtZWFzdC0yOjQyYzlmMzlkLWM5MzUtNGQ1Yy1hODQ1LTVjODgxNWM3OWVlMyIsImVtYWlsQ2xpZW50SWQiOiI1Zmw3ZGc3bXZ1NTM0bzl2ZmpiYzZoajMxcCJ9',
}, defaults.TEMPLATE_NEXT)

export const router = createHashRouter([
Expand Down
118 changes: 25 additions & 93 deletions src/utils/useEmailAuth.ts
Original file line number Diff line number Diff line change
@@ -1,113 +1,45 @@
import { useMemo, useState } from 'react'
import {
CognitoIdentityProviderClient,
InitiateAuthCommand, RespondToAuthChallengeCommand, SignUpCommand,
UserLambdaValidationException
} from '@aws-sdk/client-cognito-identity-provider'

interface EmailAuthConfig {
region: string
clientId: string
onSuccess: (idToken: string) => void
}
import { useState } from 'react'
import { sequence } from '../main'


export function useEmailAuth({ region, clientId, onSuccess }: EmailAuthConfig) {
export function useEmailAuth({ onSuccess }: { onSuccess: (idToken: string) => void }) {
const [email, setEmail] = useState("")
const [error, setError] = useState<unknown>()
const [loading, setLoading] = useState(false)
const [challengeSession, setChallengeSession] = useState('')

const client = useMemo(
() => new CognitoIdentityProviderClient({ region }),
[region],
)

const signUp = async (email: string) => {
const cmd = new SignUpCommand({
ClientId: clientId,
Username: email,
Password: 'aB1%' + getRandomString(14),
UserAttributes: [{Name: 'email', Value: email}],
})
await client.send(cmd)
}
const [instance, setInstance] = useState('')

const initiateAuth = (email: string) => {
const cmd = new InitiateAuthCommand({
AuthFlow: 'CUSTOM_AUTH',
ClientId: clientId,
AuthParameters: {
USERNAME: email,
}
})
setEmail(email)
const initiateAuth = async (email: string) => {
setLoading(true)

;(async () => {
while (true) {
try {
const res = await client.send(cmd)
if (!res.Session) {
throw new Error("response session is empty")
}
setChallengeSession(res.Session)
setLoading(false)
break
} catch (e) {
if (e instanceof UserLambdaValidationException) {
if (e.message.includes("user not found")) {
await signUp(email)
continue
}
}
setError(e)
setLoading(false)
break
}
}
})()
try {
const { instance } = await sequence.email.initiateAuth({ email })
setInstance(instance)
setEmail(email)
} catch (e: any) {
setError(e.message || "Unknown error")
} finally {
setLoading(false)
}
}

const sendChallengeAnswer = (answer: string) => {
const cmd = new RespondToAuthChallengeCommand({
ClientId: clientId,
Session: challengeSession,
ChallengeName: 'CUSTOM_CHALLENGE',
ChallengeResponses: { USERNAME: email, ANSWER: answer },
})
const sendChallengeAnswer = async (answer: string) => {
setLoading(true)

;(async () => {
try {
const res = await client.send(cmd)
if (!res.AuthenticationResult) {
throw new Error('AuthenticationResult is empty')
}
onSuccess(res.AuthenticationResult.IdToken!)
} catch (e) {
setError(e)
} finally {
setLoading(false)
}
})()
try {
const { idToken } = await sequence.email.finalizeAuth({ instance, answer, email })
onSuccess(idToken)
} catch (e: any) {
setError(e.message || "Unknown error")
} finally {
setLoading(false)
}
}

return {
inProgress: loading || !!challengeSession,
inProgress: loading || !!instance,
loading,
error,
initiateAuth,
sendChallengeAnswer: challengeSession ? sendChallengeAnswer : undefined,
sendChallengeAnswer: instance ? sendChallengeAnswer : undefined,
}
}

function getRandomString(len: number) {
const randomValues = new Uint8Array(len);
window.crypto.getRandomValues(randomValues);
return Array.from(randomValues).map(intToHex).join('');
}

function intToHex(nr: number) {
return nr.toString(16).padStart(2, '0');
}
Loading

0 comments on commit 7892675

Please sign in to comment.