forked from wslyvh/nexth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsiwe.tsx
132 lines (113 loc) · 3.7 KB
/
siwe.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { useAccount, useNetwork, useSignMessage } from 'wagmi'
import { SiweMessage } from 'siwe'
import { useEffect, useState } from 'react'
import { SITE_NAME } from 'utils/config'
import { Button, ListItem, UnorderedList } from '@chakra-ui/react'
import { LinkComponent } from 'components/layout/LinkComponent'
import { NextSeo } from 'next-seo'
import { HeadingComponent } from 'components/layout/HeadingComponent'
function SignInButton() {
const [loggedInAddress, setLoggedInAddress] = useState('')
const { address } = useAccount()
const { chain } = useNetwork()
const { signMessageAsync } = useSignMessage()
// Fetch user when:
useEffect(() => {
const handler = async () => {
try {
const res = await fetch('/api/account')
const json = await res.json()
if (json.address) {
setLoggedInAddress(json.address)
}
} catch (_error) {}
}
// 1. page loads
handler()
// 2. window is focused (in case user logs out of another window)
window.addEventListener('focus', handler)
return () => window.removeEventListener('focus', handler)
}, [])
const signIn = async () => {
try {
const chainId = chain?.id
if (!address || !chainId) return
// 1. Get random nonce from API
const nonceRes = await fetch('/api/account/nonce')
const nonce = await nonceRes.text()
// 2. Create SIWE message with pre-fetched nonce and sign with wallet
const message = new SiweMessage({
domain: window.location.host,
address,
statement: `Sign in with Ethereum to ${SITE_NAME}.`,
uri: window.location.origin,
version: '1',
chainId,
nonce: nonce,
})
// 3. Sign message
const signature = await signMessageAsync({
message: message.prepareMessage(),
})
// 3. Verify signature
const verifyRes = await fetch('/api/account/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message, signature }),
})
if (!verifyRes.ok) throw new Error('Error verifying message')
setLoggedInAddress(address)
} catch (error) {
console.error(error)
setLoggedInAddress('')
}
}
async function logout() {
await fetch('/api/account/logout')
setLoggedInAddress('')
}
return (
<div>
<HeadingComponent as="h3">Try it out</HeadingComponent>
<p>
<Button onClick={signIn}>Sign-in With Ethereum</Button>
</p>
{loggedInAddress && (
<div>
<HeadingComponent as="h3">Signed in as</HeadingComponent>
<p>{loggedInAddress}</p>
<p>
<Button onClick={logout}>Sign Out</Button>
</p>
</div>
)}
</div>
)
}
export default function SiweExample() {
const { isConnected } = useAccount()
if (isConnected) {
return (
<div>
<NextSeo title="Sign-in With Ethereum" />
<HeadingComponent as="h2">Sign-in with Ethereum</HeadingComponent>
<p>
Sign-in with Ethereum is a new form of authentication that enables users to control their digital identity with their Ethereum account and
ENS profile instead of relying on a traditional intermediary.
</p>
<UnorderedList>
<ListItem>
<LinkComponent href="https://login.xyz/">More info</LinkComponent>
</ListItem>
<ListItem>
<LinkComponent href="https://wagmi.sh/examples/sign-in-with-ethereum">Wagmi Docs</LinkComponent>
</ListItem>
</UnorderedList>
<SignInButton />
</div>
)
}
return <div>Connect your wallet first to sign-in with Ethereum.</div>
}