Use EIP-4361 login method

This commit is contained in:
silverpill 2022-02-09 01:34:56 +00:00
parent 968ebe07b2
commit f876b509ba
3 changed files with 75 additions and 12 deletions

View file

@ -81,6 +81,28 @@ export async function getAccessToken(user: UserLoginForm): Promise<string> {
} }
} }
export async function getAccessTokenEip4361(
message: string,
signature: string,
): Promise<string> {
const url = `${BACKEND_URL}/oauth/token`
const tokenRequestData = {
grant_type: "eip4361",
message: message,
signature: signature,
}
const response = await http(url, {
method: "POST",
json: tokenRequestData,
})
const data = await response.json()
if (response.status !== 200) {
throw new Error(data.message)
} else {
return data.access_token
}
}
export async function getCurrentUser(authToken: string): Promise<User | null> { export async function getCurrentUser(authToken: string): Promise<User | null> {
const url = `${BACKEND_URL}/api/v1/accounts/verify_credentials` const url = `${BACKEND_URL}/api/v1/accounts/verify_credentials`
const response = await http(url, { authToken }) const response = await http(url, { authToken })

View file

@ -58,3 +58,33 @@ export async function getWalletSignature(
} }
return signature return signature
} }
function generateRandomString(len: number): string {
const arr = new Uint8Array(len / 2)
window.crypto.getRandomValues(arr)
return Array.from(arr, (val) => val.toString(16).padStart(2, "0")).join("")
}
export async function createEip4361_SignedMessage(
signer: Signer,
domain: string,
statement: string,
): Promise<{ message: string, signature: string }> {
const address = await signer.getAddress()
const uri = window.location.origin
const nonce = generateRandomString(16)
const issuedAt = new Date().toISOString()
const message = `${domain} wants you to sign in with your Ethereum account:
${address}
${statement}
URI: ${uri}
Version: 1
Chain ID: 1
Nonce: ${nonce}
Issued At: ${issuedAt}`
const signature = await signer.signMessage(message)
return { message, signature }
}

View file

@ -53,12 +53,23 @@
<script lang="ts"> <script lang="ts">
import { Options, Vue, setup } from "vue-class-component" import { Options, Vue, setup } from "vue-class-component"
import { createUser, getAccessToken, getCurrentUser } from "@/api/users" import {
createUser,
getAccessToken,
getAccessTokenEip4361,
getCurrentUser,
} from "@/api/users"
import { InstanceInfo } from "@/api/instance" import { InstanceInfo } from "@/api/instance"
import Loader from "@/components/Loader.vue" import Loader from "@/components/Loader.vue"
import { useInstanceInfo } from "@/store/instance" import { useInstanceInfo } from "@/store/instance"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
import { getWeb3Provider, getWalletAddress, getWalletSignature } from "@/utils/ethereum" import {
getWeb3Provider,
getWallet,
getWalletAddress,
getWalletSignature,
createEip4361_SignedMessage,
} from "@/utils/ethereum"
@Options({ @Options({
components: { Loader }, components: { Loader },
@ -120,24 +131,24 @@ export default class LandingPage extends Vue {
async login() { async login() {
this.loginErrorMessage = null this.loginErrorMessage = null
const provider = getWeb3Provider() if (!this.store.instance) {
if (!provider || !this.store.instance) {
return return
} }
const instanceHost = this.store.instance.uri
const loginMessage = this.store.instance.login_message const loginMessage = this.store.instance.login_message
const walletAddress = await getWalletAddress(provider) const signer = await getWallet()
if (!walletAddress) { if (!signer) {
return return
} }
const signature = await getWalletSignature(provider, walletAddress, loginMessage) const { message, signature } = await createEip4361_SignedMessage(
if (!signature) { signer,
return instanceHost,
} loginMessage,
const loginData = { wallet_address: walletAddress, signature } )
let user let user
let authToken let authToken
try { try {
authToken = await getAccessToken(loginData) authToken = await getAccessTokenEip4361(message, signature)
user = await getCurrentUser(authToken) user = await getCurrentUser(authToken)
} catch (error) { } catch (error) {
this.loginErrorMessage = error.message this.loginErrorMessage = error.message