Laravel 10 Sanctum with Next js 14 - Store dan akses token

jadi saya mau pisahin antara backend dan frontend tapi saya bingung di mana tempat yg aman untuk simpan token dari laravel setelah authentication, kemudian bagaimana implementasi protect route di next js nya ?

Untuk hal yg sudah saya lakukan:

1.setelah login, token kemudian saya simpan token di localStorage, dilanjut dengan redirect menggunakan ke halaman users (abaikan redirect menggunakan window.location.href)

//next js
// app/login/page.js
        axios.get('http://localhost:8000/sanctum/csrf-cookie').then(response => {
            axios({
                url: "http://localhost:8000/api/auth/login",
                method: "POST",
                data: _this.serialize()
            })
                .then(res => {
                    if (res.status == 200) {
                        localStorage.setItem('token', JSON.stringify(res.data))
                        window.location.href = "http://localhost:3000/users"
                    } else {
                        toastr.error('', res.msg)
                    }
                })
        });
  1. di halaman Users, sebenarnya saya tetap ingin halaman sebagai server component, tapi dikarenakan saya harus menggunakan hook useEffect, untuk mengakses objct window dan localStorage, akhirnya saya tambahakan use client agar menjadi client component
//next js
// app/users/page.js
'use client'

import React, { useEffect } from 'react'
import UserLists from './_components/UserLists'

export default function users() {
    useEffect(function () {
        if (typeof window !== 'undefined' && window.localStorage) {
            const token = localStorage.getItem('token')
            if (token == null) window.location.href = "/login"

        }
    }, [])
    return (
        <>
            <UserLists/>
        </>
    )
}

  1. sampai disini sebenernya secara fungsi sudah berjalan, tapi belum sempurna karena sebagian tampilan di halaman Users akan tetap ke render, sebelum diredirect ke halaman login ( jika token tidak ada)

saya minta bantuan dari master2 disini, saran atau mungkin punya cara yg lebih bagus untuk implementasi otentikasi seperti kasus saya ini dan mudah2an bahasa saya mudah untuk dimengerti , terima kasih

avatar naufalhfzhn
@naufalhfzhn

172 Kontribusi 59 Poin

Diperbarui 1 bulan yang lalu

3 Jawaban:

Jawaban Terpilih

Secara umum, disarankan untuk menyimpan token pada cookies (httponly cookie)

ref:

  • https://stackoverflow.com/questions/76086733/can-i-store-jwt-token-in-local-storage-while-using-next-js
  • https://blog.logrocket.com/jwt-authentication-best-practices/
  • https://www.linkedin.com/pulse/jwt-token-where-store-browser-deepak-jha/

Saya belum pernah bikin Nextjs client app untuk konsumsi JWT token, tapi sepertinya tempat yang tepat adalah middleware nya

ref:

  • https://stackoverflow.com/questions/73431746/jwt-authentication-with-nextjs
  • https://www.makeuseof.com/token-authentication-nextjs-using-jwt/
avatar hilmanski
@hilmanski

2670 Kontribusi 2132 Poin

Dipost 3 bulan yang lalu

Tanggapan

Betul bang hilman, untuk konsumsi token dan protecting route lebih tepat di middleware supaya lebih terpusat, terima kasih bang hilman

Penyimpanan Token Menggunakan localStorage untuk menyimpan token memang praktis, tapi kurang aman dari serangan seperti Cross-Site Scripting (XSS). Sebagai alternatif, Anda bisa mempertimbangkan penggunaan HTTP Only Cookies. Laravel Sanctum menyediakan cara mudah untuk mengatur ini. Cookies HTTP Only tidak dapat diakses melalui JavaScript, yang meningkatkan keamanan.

  1. Protect Route di Next.js Menggunakan useEffect untuk redirect memang bekerja, tapi seperti yang Anda sebutkan, ada masalah dengan rendering. Ini bisa kita atasi dengan beberapa cara:

a. Server-Side Rendering (SSR) Anda bisa menggunakan getServerSideProps di Next.js untuk memeriksa token sebelum halaman dirender. Ini mencegah rendering halaman jika pengguna tidak terautentikasi.

Contoh kode:

export async function getServerSideProps(context) {
    const token = context.req.cookies.token; // Asumsi token disimpan dalam cookie

    if (!token) {
        // Redirect jika tidak ada token
        return {
            redirect: {
                destination: '/login',
                permanent: false,
            },
        };
    }

    // Lanjutkan rendering halaman jika ada token
    return { props: {} };
}

b. Client-Side dengan Custom Hook Anda bisa membuat custom hook untuk autentikasi di sisi klien. Hook ini akan menangani redirect dan kondisi token.

  1. Menangani Token di Laravel Pastikan Anda mengatur middleware dan konfigurasi Sanctum dengan benar untuk menangani token dan sesi.

  2. Konsiderasi Lain Refresh Token: Pertimbangkan implementasi refresh token untuk meningkatkan keamanan. Validasi Token: Pastikan token divalidasi di setiap request ke server.

avatar adamajalah27
@adamajalah27

119 Kontribusi 40 Poin

Dipost 3 bulan yang lalu

Tanggapan

Terima kasih bang adam sudah membantu berikan jawaban.

Tapi setelah saya baca lagi dokumentasi next js, solusi dan bang adam lebih cocok untuk aplikasi next js yg menggunakan pages router

sedangkan saya menggunakan next js 13 dimana secara default menggunakan app router

tapi dengan bantuan instruksi dari bang adam, saya memakai beberapa logika dari jawaban bang adam yg bisa saya terapkan di app router ini

dan dengan adanya fitur middleware yg sepertinya baru ada di next 13 ini, sangat membantu sekali untuk sistem yg akan saya buat saat ini

Terima kasih banyak bang adam untuk jawaban dan penjelasan yg cukup jelas

untuk hasil kodingannya saya nanti akan share disini, siapa tau temen2 disini ada yg mengalami kasus yg sama

[UPDATE SNIPPET CODE] maaf telat banget share nya, tapi karena saya juga sudah janji jadi tetap saya bagikan

untuk di Laravelnya:

public function login(Request $request)
    {
//validation process
     $tokenCookie = cookie('token', $token);
     return response($response)->cookie($tokenCookie);  // langsung chain untuk create cookie yg berisi token
    }

kemudian pada middleware.js di next seperti

export function middleware(request) {
    let token = request.cookies.get('token')  // untuk mendapatkan token

    if (request.nextUrl.pathname.startsWith('/login')) {
        if (token && token != "undefined") return NextResponse.redirect('http://localhost:3000/dashboard')

        return NextResponse.next()
    }
    else {
        if (token == undefined) return NextResponse.redirect('http://localhost:3000/login')

        return NextResponse.next()

    }

}

semoga cukup mudah untuk dipahami

sangat terbuka untuk saran agar bisa lebih baik kodenya dari segi security atau optimasi nya

sekian dan terima kasih

avatar naufalhfzhn
@naufalhfzhn

172 Kontribusi 59 Poin

Dipost 1 bulan yang lalu

Tanggapan

terima kasih sudah sharing Naufal

Login untuk ikut Jawaban