I have read a lot about netlify identity and gotrue. But I do not know whats the best way to guard my static pages.
this is my function that will be called before every route change
const auth = new GoTrue({
APIUrl: 'https://domain.netlify.app/.netlify/identity',
setCookie: true,
})
app.router.beforeEach((to, from, next) => {
// check if page is inside privat folder
const auth_required = to.path.split('/')[1] === 'privat'
// no auth required: just procced
if(!auth_required) return next()
// auth is required
// if user is logged in
if(store.getters['auth/authenticated']) {
// check if token is valid
axios
.get('/.netlify/functions/route-guard')
.then(() => next())
.catch(() => app.router.push('/login'))
} else {
//not logged in redirect
app.router.push('/login')
}
})
and my netlify function
Do I need to verify the token, in case someone might have tempered the token? Is this still possible if I store the token only inside a httpOnly cookie?
exports.handler = async function(event, context) {
const { identity } = context.clientContext
// do i need to verify the token somehow?
if(identity.token) {
return {
statusCode: 200,
}
} else {
return {
statusCode: 401,
body: JSON.stringify({message: '401 Unauthorized'})
}
}
}
Or is above completely too much and it’s save enough to check if a user exists in the auth object?
Using identity without serverless function is not my problem. (see third code snippet)
I wanted to know if the third code snippet is enough for security for static rendered pages or if I should better go with a serverless function and somehow verify the token every time the user accesses a protected route.
When a cookie is set using HttpOnly, there’s no way for JavaScript to manipulate it, so you can at least remove the tampering problem from the equation. But I believe auth.currentUser() is not enough too. The way it works is:
When you login, a value is stored in localstorage with the name gotrue.user and that value === the response you get from auth.login(email, password, remember). When you call auth.currentUser(), it simply takes that value from localstorage and gets done with it (is what I have understood by reading the code):
The way I have planned to do it (just started working on a project today with similar goals and tools stack ) is:
Check if a user is logged in
If yes, validate their token from the server
Use Vuex store to save a property as user: true
Check for that property in NavigationGuards.
From my understanding, that should suffice to secure the app for most needs.
this is my code so far in nuxtjs, if you like to take a look I’m a UI- Designer, with some frontend skills, but this authentication is absolutely new to me.
const auth = new GoTrue({
APIUrl: 'https://domain.netlify.app/.netlify/identity',
setCookie: true,
})
app.router.beforeEach((to, from, next) => {
// get path (folder)
const path = to.path.split('/')[1]
// if no auth required: just proceed
if(path !== 'admin') return next()
// if I stay in the same directory skip server check, because it was already checked before
const pathFrom = from.path.split('/')[1]
if(path === pathFrom) return next()
const user = auth.currentUser()
if(user) {
axios
.get('/.netlify/functions/route-guard', {
headers: {
Authorization: `Bearer ${user.token.access_token}`
}
})
.then(() => next())
.catch(() => next({ path: '/login' }))
} else {
next({ path: '/login' })
}
})
my server function
exports.handler = async function(event, context) {
// the function is called with authorization header, so clientContext contains a valid certified user
const { user, identity } = context.clientContext
if(user) {
return {
statusCode: 200,
body: JSON.stringify({user})
}
} else {
return {
statusCode: 401,
body: JSON.stringify({message: '401 Unauthorized'})
}
}
}
That looks fine to me. The only thing I’d worry about is the function calls. How many times are users going to switch pages on your website? If the number is high, you might deplete your function calls pretty fast.
This is the only reason I suggested using Vuex as you can authenticate once in your website’s lifecycle and be done with it. As long as the user is not going to linger on your website for as long as the token remains valid, I think this way would help you save some function calls (and in turn, make navigation faster).
to reduce the functioncalls I have this code, because everything with authentication I have inside a admin folder
// new path
const path = to.path.split('/')[1]
// old path
const pathFrom = from.path.split('/')[1]
// if users are in the same directory skip function call
if(path === pathFrom) return next()
Yes, I saw that, but that’s what I was asking. How many times do you expect your users to go back and forth from that folder to elsewhere and return back to that folder. If that’s not a huge number, then you’re good. Or else, you might have to consider alternatives.
But how I can secure the vuex so that I can’t manipulate it from the outside? I can easily add a user from console, and get so access to protected routes
document.getElementById('__nuxt').__vue__.$store.commit('auth/user', {user:'injected from console'})
No you’re not thinking too complicated, rather taking essential steps to stay secure. I gave some articles a good read and maybe you’d get some insights too:
In short, any client-side data as expected cannot be considered secure. So checking for access token on each route change is one way to go. Another way would be to store some token in external database for the first time and then checking that from client-side. The key used in the client-side should only have read rights.
In any case, backend calls are going to cost you, so as long as budget/number of calls is not an issue, that would be a good way to secure your stuff.