Nuxt
Nuxt
@orria/tapok/nuxt реэкспортирует browser-клиенты. Запускайте их только на клиенте. Backend helpers импортируются отдельно из @orria/tapok/server в server route.
Hosted
<!-- pages/login.vue -->
<script setup lang="ts">
import { Tapok } from '@orria/tapok/nuxt'
const tapok = new Tapok()
async function login() {
const result = await tapok.login() // вызывается из click в browser
await $fetch('/api/session', {
method: 'POST',
body: { token: result.token },
})
}
</script>
<template><button @click="login">Войти через Tapok</button></template>
// server/api/session.post.ts — псевдокод
import { verifyHostedToken } from '@orria/tapok/server'
export default defineEventHandler(async event => {
const { token } = await readBody(event)
const verified = await verifyHostedToken(token, {
origin: 'https://app.example', // доверенная runtime config
})
const session = await sessions.create(verified.user.uid)
setCookie(event, 'session', session, { httpOnly: true, secure: true })
})
Connect
<!-- pages/auth/callback.vue -->
<script setup lang="ts">
import { createTapokConnect } from '@orria/tapok/nuxt'
const connect = createTapokConnect({
clientId: 'tapok_…',
redirectUri: 'https://app.example/auth/callback',
scopes: ['session', 'profile:display_name'],
})
onMounted(async () => {
const callback = connect.finishSignIn()
if (callback) await $fetch('/api/connect/exchange', { method: 'POST', body: callback })
})
</script>
<template><p>Завершаем вход…</p></template>
// server/api/connect/exchange.post.ts — псевдокод
import { exchangeConnectCode } from '@orria/tapok/server'
export default defineEventHandler(async event => {
const callback = await readBody(event)
const token = await exchangeConnectCode({
clientId: runtimeConfig.tapokClientId,
apiKey: runtimeConfig.tapokApiKey,
code: callback.code,
codeVerifier: callback.codeVerifier,
redirectUri: 'https://app.example/auth/callback',
})
return createOwnSession(event, token.pairwise_sub)
})
tapokApiKey должен находиться в private runtime config, а не в runtimeConfig.public.