✨ feat (auth): server side proxy login request
This commit is contained in:
@@ -1,22 +1,41 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import PasswordInput from '~/components/PasswordInput.vue'
|
|
||||||
import { Loader2 } from 'lucide-vue-next'
|
import { Loader2 } from 'lucide-vue-next'
|
||||||
|
|
||||||
const email = ref('demo@gmail.com')
|
const email = ref('demo@gmail.com')
|
||||||
const password = ref('password')
|
const password = ref('password')
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
|
|
||||||
function onSubmit(event: Event) {
|
async function onSubmit(event: Event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
if (!email.value || !password.value) return
|
if (!email.value || !password.value) return
|
||||||
|
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
|
|
||||||
setTimeout(() => {
|
try {
|
||||||
if (email.value === 'demo@gmail.com' && password.value === 'password') navigateTo('/')
|
const { data: respData } = await useFetch('/api/v1/authentication/login', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: 'system',
|
||||||
|
password: 'the-SYSTEM-1234',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const resp = respData.value
|
||||||
|
if (!resp) throw new Error('No response')
|
||||||
|
|
||||||
|
const { data: rawdata, meta } = resp
|
||||||
|
console.log('DATA', rawdata)
|
||||||
|
console.log('META', meta)
|
||||||
|
|
||||||
|
if (meta.status === 'verified') {
|
||||||
|
await nextTick()
|
||||||
|
navigateTo('/')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login failed:', error)
|
||||||
|
} finally {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}, 3000)
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
+23
-21
@@ -1,5 +1,5 @@
|
|||||||
import antfu from "@antfu/eslint-config";
|
import antfu from '@antfu/eslint-config'
|
||||||
import withNuxt from "./.nuxt/eslint.config.mjs";
|
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||||
|
|
||||||
export default withNuxt(
|
export default withNuxt(
|
||||||
antfu(
|
antfu(
|
||||||
@@ -9,7 +9,7 @@ export default withNuxt(
|
|||||||
// Relaxed stylistic options
|
// Relaxed stylistic options
|
||||||
stylistic: {
|
stylistic: {
|
||||||
semi: false,
|
semi: false,
|
||||||
quotes: "single",
|
quotes: 'single',
|
||||||
// Less strict formatting
|
// Less strict formatting
|
||||||
jsx: false,
|
jsx: false,
|
||||||
},
|
},
|
||||||
@@ -17,34 +17,36 @@ export default withNuxt(
|
|||||||
{
|
{
|
||||||
rules: {
|
rules: {
|
||||||
// Basic rules
|
// Basic rules
|
||||||
quotes: ["error", "single", { avoidEscape: true }],
|
quotes: ['error', 'single', { avoidEscape: true }],
|
||||||
"style/no-trailing-spaces": ["error", { ignoreComments: true }],
|
'style/no-trailing-spaces': ['error', { ignoreComments: true }],
|
||||||
|
|
||||||
|
'no-console': 'off',
|
||||||
|
|
||||||
// Relax strict formatting rules
|
// Relax strict formatting rules
|
||||||
"style/brace-style": "off", // Allow inline if
|
'style/brace-style': 'off', // Allow inline if
|
||||||
curly: ["error", "multi-line"], // Only require braces for multi-line
|
curly: ['error', 'multi-line'], // Only require braces for multi-line
|
||||||
"style/arrow-parens": "off",
|
'style/arrow-parens': 'off',
|
||||||
|
|
||||||
// UnoCSS - make it warning instead of error, or disable completely
|
// UnoCSS - make it warning instead of error, or disable completely
|
||||||
"unocss/order": "off", // atau 'off' untuk disable
|
'unocss/order': 'off', // atau 'off' untuk disable
|
||||||
|
|
||||||
// Vue specific - relax template formatting
|
// Vue specific - relax template formatting
|
||||||
"vue/html-indent": "off",
|
'vue/html-indent': 'off',
|
||||||
"vue/max-attributes-per-line": "off",
|
'vue/max-attributes-per-line': 'off',
|
||||||
"vue/singleline-html-element-content-newline": "off",
|
'vue/singleline-html-element-content-newline': 'off',
|
||||||
"vue/multiline-html-element-content-newline": "off",
|
'vue/multiline-html-element-content-newline': 'off',
|
||||||
"vue/html-self-closing": "off",
|
'vue/html-self-closing': 'off',
|
||||||
|
|
||||||
// Allow more flexible code style
|
// Allow more flexible code style
|
||||||
"style/max-statements-per-line": ["error", { max: 3 }],
|
'style/max-statements-per-line': ['error', { max: 3 }],
|
||||||
"antfu/if-newline": "off", // Disable newline after if requirement
|
'antfu/if-newline': 'off', // Disable newline after if requirement
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ["**/*.md"],
|
files: ['**/*.md'],
|
||||||
rules: {
|
rules: {
|
||||||
"style/no-trailing-spaces": "off",
|
'style/no-trailing-spaces': 'off',
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
),
|
)
|
||||||
);
|
)
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
|
runtimeConfig: {
|
||||||
|
API_ORIGIN: process.env.API_ORIGIN || 'https://main-api.dev-hopis.sabbi.id',
|
||||||
|
},
|
||||||
modules: [
|
modules: [
|
||||||
'@unocss/nuxt',
|
'@unocss/nuxt',
|
||||||
'shadcn-nuxt',
|
'shadcn-nuxt',
|
||||||
|
|||||||
+5
-4
@@ -19,14 +19,12 @@
|
|||||||
"@unovis/ts": "^1.5.1",
|
"@unovis/ts": "^1.5.1",
|
||||||
"@unovis/vue": "^1.5.1",
|
"@unovis/vue": "^1.5.1",
|
||||||
"embla-carousel": "^8.5.2",
|
"embla-carousel": "^8.5.2",
|
||||||
"embla-carousel-vue": "^8.5.2"
|
"embla-carousel-vue": "^8.5.2",
|
||||||
|
"h3": "^1.15.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^4.10.1",
|
"@antfu/eslint-config": "^4.10.1",
|
||||||
"@nuxt/eslint": "^1.2.0",
|
"@nuxt/eslint": "^1.2.0",
|
||||||
"prettier": "^3.6.2",
|
|
||||||
"prettier-plugin-tailwindcss": "^0.5.14",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"@nuxt/icon": "^1.11.0",
|
"@nuxt/icon": "^1.11.0",
|
||||||
"@nuxtjs/color-mode": "^3.5.2",
|
"@nuxtjs/color-mode": "^3.5.2",
|
||||||
"@pinia/nuxt": "^0.5.1",
|
"@pinia/nuxt": "^0.5.1",
|
||||||
@@ -39,9 +37,12 @@
|
|||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint": "^9.22.0",
|
"eslint": "^9.22.0",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-format": "^1.0.1",
|
"eslint-plugin-format": "^1.0.1",
|
||||||
"lucide-vue-next": "^0.482.0",
|
"lucide-vue-next": "^0.482.0",
|
||||||
"nuxt": "^4.0.1",
|
"nuxt": "^4.0.1",
|
||||||
|
"prettier": "^3.6.2",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.5.14",
|
||||||
"radix-vue": "^1.9.17",
|
"radix-vue": "^1.9.17",
|
||||||
"shadcn-nuxt": "^0.10.4",
|
"shadcn-nuxt": "^0.10.4",
|
||||||
"tailwind-merge": "^2.6.0",
|
"tailwind-merge": "^2.6.0",
|
||||||
|
|||||||
Generated
+3
-10
@@ -26,6 +26,9 @@ dependencies:
|
|||||||
embla-carousel-vue:
|
embla-carousel-vue:
|
||||||
specifier: ^8.5.2
|
specifier: ^8.5.2
|
||||||
version: 8.6.0(vue@3.5.18)
|
version: 8.6.0(vue@3.5.18)
|
||||||
|
h3:
|
||||||
|
specifier: ^1.15.4
|
||||||
|
version: 1.15.4
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@antfu/eslint-config':
|
'@antfu/eslint-config':
|
||||||
@@ -5279,7 +5282,6 @@ packages:
|
|||||||
|
|
||||||
/cookie-es@1.2.2:
|
/cookie-es@1.2.2:
|
||||||
resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
|
resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/cookie-es@2.0.0:
|
/cookie-es@2.0.0:
|
||||||
resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==}
|
resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==}
|
||||||
@@ -5365,7 +5367,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
|
resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
uncrypto: 0.1.3
|
uncrypto: 0.1.3
|
||||||
dev: true
|
|
||||||
|
|
||||||
/css-declaration-sorter@7.2.0(postcss@8.5.6):
|
/css-declaration-sorter@7.2.0(postcss@8.5.6):
|
||||||
resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==}
|
resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==}
|
||||||
@@ -5865,7 +5866,6 @@ packages:
|
|||||||
|
|
||||||
/defu@6.1.4:
|
/defu@6.1.4:
|
||||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/delaunator@5.0.1:
|
/delaunator@5.0.1:
|
||||||
resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==}
|
resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==}
|
||||||
@@ -5890,7 +5890,6 @@ packages:
|
|||||||
|
|
||||||
/destr@2.0.5:
|
/destr@2.0.5:
|
||||||
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/detect-libc@1.0.3:
|
/detect-libc@1.0.3:
|
||||||
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
|
||||||
@@ -7320,7 +7319,6 @@ packages:
|
|||||||
radix3: 1.1.2
|
radix3: 1.1.2
|
||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
uncrypto: 0.1.3
|
uncrypto: 0.1.3
|
||||||
dev: true
|
|
||||||
|
|
||||||
/has-flag@4.0.0:
|
/has-flag@4.0.0:
|
||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
@@ -7486,7 +7484,6 @@ packages:
|
|||||||
|
|
||||||
/iron-webcrypto@1.2.1:
|
/iron-webcrypto@1.2.1:
|
||||||
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
|
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/is-arrayish@0.2.1:
|
/is-arrayish@0.2.1:
|
||||||
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||||
@@ -8817,7 +8814,6 @@ packages:
|
|||||||
|
|
||||||
/node-mock-http@1.0.2:
|
/node-mock-http@1.0.2:
|
||||||
resolution: {integrity: sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==}
|
resolution: {integrity: sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/node-releases@2.0.19:
|
/node-releases@2.0.19:
|
||||||
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
|
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
|
||||||
@@ -9945,7 +9941,6 @@ packages:
|
|||||||
|
|
||||||
/radix3@1.1.2:
|
/radix3@1.1.2:
|
||||||
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
|
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/randombytes@2.1.0:
|
/randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
@@ -10883,7 +10878,6 @@ packages:
|
|||||||
|
|
||||||
/ufo@1.6.1:
|
/ufo@1.6.1:
|
||||||
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
|
resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ultrahtml@1.6.0:
|
/ultrahtml@1.6.0:
|
||||||
resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
|
resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==}
|
||||||
@@ -10900,7 +10894,6 @@ packages:
|
|||||||
|
|
||||||
/uncrypto@0.1.3:
|
/uncrypto@0.1.3:
|
||||||
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
|
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/unctx@2.4.1:
|
/unctx@2.4.1:
|
||||||
resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==}
|
resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { useRuntimeConfig } from '#imports'
|
||||||
|
import { getRequestURL, readBody, setCookie } from 'h3'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event)
|
||||||
|
const url = getRequestURL(event)
|
||||||
|
const config = useRuntimeConfig()
|
||||||
|
|
||||||
|
const apiOrigin = config.API_ORIGIN
|
||||||
|
|
||||||
|
const externalUrl = apiOrigin + url.pathname.replace(/^\/api/, '') + url.search
|
||||||
|
|
||||||
|
const resp = await fetch(externalUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (resp.status === 200) {
|
||||||
|
const data = await resp.json()
|
||||||
|
|
||||||
|
if (data?.data?.accessToken) {
|
||||||
|
setCookie(event, 'authentication', data.data.accessToken, {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: 'strict',
|
||||||
|
maxAge: 60 * 60 * 24,
|
||||||
|
})
|
||||||
|
|
||||||
|
delete data.data.accessToken
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(await resp.text(), {
|
||||||
|
status: resp.status,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': resp.headers.get('content-type') || 'text/plain',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user