feat(examples): add reset password ticket expired workarounds in the examples (#2590)
fixes https://github.com/nhost/nhost/issues/2314
This commit is contained in:
committed by
GitHub
parent
f0a994a26e
commit
08a7dd9894
6
.changeset/calm-bottles-do.md
Normal file
6
.changeset/calm-bottles-do.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@nhost-examples/react-apollo': minor
|
||||
'@nhost-examples/vue-apollo': minor
|
||||
---
|
||||
|
||||
feat: add example workaround to the reset password ticket expired issue
|
||||
@@ -8,7 +8,7 @@
|
||||
<h2>Verify Email</h2>
|
||||
<p>Use this link to verify your email:</p>
|
||||
<p>
|
||||
<a href="${link}"> Verify Email </a>
|
||||
<a href="${clientUrl}/verify?ticket=${ticket}&redirectTo=${redirectTo}&type=emailVerify"> Verify Email </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h2>Reset Password</h2>
|
||||
<p>Use this link to reset your password:</p>
|
||||
<p>
|
||||
<a href="${link}"> Reset password </a>
|
||||
<a href="${clientUrl}/verify?ticket=${ticket}&redirectTo=${redirectTo}&type=emailVerify"> Reset password </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Magic Link</h2>
|
||||
<p>Use this link to securely sign in:</p>
|
||||
<p>
|
||||
<a href="${link}"> Sign In </a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Magic Link</h2>
|
||||
<p>Use this link to securely sign in:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
Verify Email
|
||||
</a>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -16,6 +16,7 @@ enableAllowList = false
|
||||
enableConsole = true
|
||||
enableRemoteSchemaPermissions = false
|
||||
enabledAPIs = ['metadata', 'graphql', 'pgdump', 'config']
|
||||
liveQueriesMultiplexedRefetchInterval = 1000
|
||||
|
||||
[hasura.logs]
|
||||
level = 'warn'
|
||||
@@ -28,7 +29,7 @@ httpPoolSize = 100
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.26.0'
|
||||
version = '0.27.0-beta13'
|
||||
|
||||
[auth.elevatedPrivileges]
|
||||
mode = 'required'
|
||||
@@ -39,6 +40,7 @@ allowedUrls = ['https://react-apollo.example.nhost.io', 'https://react-apollo.ex
|
||||
|
||||
[auth.signUp]
|
||||
enabled = true
|
||||
disableNewUsers = false
|
||||
|
||||
[auth.user]
|
||||
[auth.user.roles]
|
||||
|
||||
@@ -16,6 +16,7 @@ import { StoragePage } from './Storage'
|
||||
|
||||
import './App.css?inline'
|
||||
import { NotesPage } from './components/notes'
|
||||
import VerifyPage from './Verify'
|
||||
const title = 'Nhost with React and Apollo'
|
||||
|
||||
function App() {
|
||||
@@ -70,6 +71,7 @@ function App() {
|
||||
</AuthGate>
|
||||
}
|
||||
/>
|
||||
<Route path="/verify" element={<VerifyPage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
<Route
|
||||
path="/sign-in/*"
|
||||
|
||||
34
examples/react-apollo/src/Verify.tsx
Normal file
34
examples/react-apollo/src/Verify.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNhostClient } from '@nhost/react'
|
||||
import { Container } from '@mantine/core'
|
||||
|
||||
const VerifyPage: React.FC = () => {
|
||||
const nhost = useNhostClient()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [searchParams] = useSearchParams()
|
||||
|
||||
useEffect(() => {
|
||||
const ticket = searchParams.get('ticket')
|
||||
const redirectTo = searchParams.get('redirectTo')
|
||||
const type = searchParams.get('type')
|
||||
|
||||
if (ticket && redirectTo && type) {
|
||||
window.location.href = `${nhost.auth.url}/verify?ticket=${ticket}&type=${type}&redirectTo=${redirectTo}`
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}, [searchParams, nhost?.auth?.url])
|
||||
|
||||
if (loading) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<span>Failed to authenticate with magick link</span>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default VerifyPage
|
||||
@@ -9,7 +9,7 @@
|
||||
<h2>Verify Email</h2>
|
||||
<p>Use this link to verify your email:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
<a href="${clientUrl}/verify?ticket=${ticket}&redirectTo=${redirectTo}&type=emailVerify">
|
||||
Verify Email
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<h2>Reset Password</h2>
|
||||
<p>Use this link to reset your password:</p>
|
||||
<p>
|
||||
<a href="${link}">
|
||||
<a href="${clientUrl}/verify?ticket=${ticket}&redirectTo=${redirectTo}&type=emailVerify">
|
||||
Reset password
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -16,6 +16,7 @@ enableAllowList = false
|
||||
enableConsole = true
|
||||
enableRemoteSchemaPermissions = false
|
||||
enabledAPIs = ['metadata', 'graphql', 'pgdump', 'config']
|
||||
liveQueriesMultiplexedRefetchInterval = 1000
|
||||
|
||||
[hasura.logs]
|
||||
level = 'warn'
|
||||
@@ -28,7 +29,7 @@ httpPoolSize = 100
|
||||
version = 18
|
||||
|
||||
[auth]
|
||||
version = '0.27.0-beta1'
|
||||
version = '0.27.0-beta13'
|
||||
|
||||
[auth.elevatedPrivileges]
|
||||
mode = 'required'
|
||||
@@ -39,6 +40,7 @@ allowedUrls = ['https://react-apollo.example.nhost.io', 'https://react-apollo.ex
|
||||
|
||||
[auth.signUp]
|
||||
enabled = true
|
||||
disableNewUsers = false
|
||||
|
||||
[auth.user]
|
||||
[auth.user.roles]
|
||||
@@ -67,7 +69,7 @@ expiresIn = 43200
|
||||
|
||||
[auth.method]
|
||||
[auth.method.anonymous]
|
||||
enabled = false
|
||||
enabled = true
|
||||
|
||||
[auth.method.emailPasswordless]
|
||||
enabled = true
|
||||
@@ -75,7 +77,7 @@ enabled = true
|
||||
[auth.method.emailPassword]
|
||||
hibpEnabled = false
|
||||
emailVerificationRequired = true
|
||||
passwordMinLength = 9
|
||||
passwordMinLength = 8
|
||||
|
||||
[auth.method.smsPasswordless]
|
||||
enabled = false
|
||||
|
||||
30
examples/vue-apollo/src/pages/VerifyEmail.vue
Normal file
30
examples/vue-apollo/src/pages/VerifyEmail.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div className="d-flex align-center flex-column">
|
||||
<v-card width="400" v-if="!loading">
|
||||
<v-card-text>Failed to authenticate with magick link</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useNhostClient } from '@nhost/vue'
|
||||
|
||||
const { nhost } = useNhostClient()
|
||||
const route = useRoute()
|
||||
|
||||
const loading = ref(true)
|
||||
|
||||
onMounted(() => {
|
||||
const ticket = route.query.ticket
|
||||
const redirectTo = route.query.redirectTo
|
||||
const type = route.query.type
|
||||
|
||||
if (ticket && redirectTo && type) {
|
||||
window.location.href = `${nhost.auth.url}/verify?ticket=${ticket}&type=${type}&redirectTo=${redirectTo}`
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
})
|
||||
</script>
|
||||
@@ -2,8 +2,20 @@
|
||||
<form @submit="handleSignIn">
|
||||
<v-text-field v-model="email" label="Email" />
|
||||
<v-text-field v-model="password" label="Password" type="password" />
|
||||
<v-btn block color="primary" class="my-1" type="submit" :disabled="isLoading" :loading="isLoading"> Sign in </v-btn>
|
||||
<v-btn
|
||||
block
|
||||
color="primary"
|
||||
class="my-1"
|
||||
type="submit"
|
||||
:disabled="isLoading"
|
||||
:loading="isLoading"
|
||||
>
|
||||
Sign in
|
||||
</v-btn>
|
||||
</form>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signin/forgot-password">
|
||||
Forgot password?
|
||||
</v-btn>
|
||||
<v-btn class="my-1" block variant="text" color="primary" to="/signin">
|
||||
← Other Sign-in Options
|
||||
</v-btn>
|
||||
|
||||
38
examples/vue-apollo/src/pages/sign-in/ForgotPassword.vue
Normal file
38
examples/vue-apollo/src/pages/sign-in/ForgotPassword.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<form @submit="handleSendResetPasswordEmail">
|
||||
<v-text-field v-model="email" label="Email" />
|
||||
<v-btn block color="primary" class="my-1" type="submit"> Reset password </v-btn>
|
||||
|
||||
<v-dialog v-model="emailSent">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<span class="text-h5">Verification email sent</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
A email has been sent to {{ email }}. Please follow the link to reset the password.
|
||||
</v-card-text>
|
||||
<v-card-actions class="justify-center d-flex">
|
||||
<v-btn text @click="emailSent = false"> Close </v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { useResetPassword } from '@nhost/vue'
|
||||
|
||||
const email = ref('')
|
||||
const emailSent = ref(false)
|
||||
|
||||
const { resetPassword } = useResetPassword({
|
||||
redirectTo: '/profile'
|
||||
})
|
||||
|
||||
const handleSendResetPasswordEmail = async (e: Event) => {
|
||||
e.preventDefault()
|
||||
await resetPassword(email)
|
||||
emailSent.value = true
|
||||
}
|
||||
</script>
|
||||
@@ -14,12 +14,15 @@ import SignUpEmailPasword from './pages/sign-up/EmailPassword.vue'
|
||||
import SignUpEmailPaswordless from './pages/sign-up/EmailPasswordless.vue'
|
||||
import SignUpEmailSecurityKey from './pages/sign-up/SecurityKey.vue'
|
||||
import SignInEmailSecurityKey from './pages/sign-in/SecurityKey.vue'
|
||||
import ForgotPassword from './pages/sign-in/ForgotPassword.vue'
|
||||
import SignUp from './pages/sign-up/IndexPage.vue'
|
||||
import Signout from './pages/SignoutPage.vue'
|
||||
import StoragePage from './pages/StoragePage.vue'
|
||||
import VerifyPage from './pages/VerifyEmail.vue'
|
||||
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
{ path: '/', component: Index, meta: { auth: true } },
|
||||
{ path: '/verify', component: VerifyPage },
|
||||
{ path: '/profile', component: Profile, meta: { auth: true } },
|
||||
{ path: '/about', component: AboutPage },
|
||||
{ path: '/signout', component: Signout },
|
||||
@@ -39,6 +42,10 @@ export const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: 'security-key',
|
||||
component: SignInEmailSecurityKey
|
||||
},
|
||||
{
|
||||
path: 'forgot-password',
|
||||
component: ForgotPassword
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user