{"id":308304,"date":"2020-05-18T07:34:08","date_gmt":"2020-05-18T14:34:08","guid":{"rendered":"https:\/\/css-tricks.com\/?p=308304"},"modified":"2020-05-18T07:34:09","modified_gmt":"2020-05-18T14:34:09","slug":"tackling-authentication-with-vue-using-restful-apis","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/tackling-authentication-with-vue-using-restful-apis\/","title":{"rendered":"Tackling Authentication With Vue Using RESTful APIs"},"content":{"rendered":"\n

Authentication (logging in!) is a crucial part of many websites. Let\u2019s look at how to go about it on a site using Vue, in the same way it can be done with any custom back end. Vue can\u2019t actually do authentication all by itself, \u2014we\u2019ll need another service for that, so we\u2019ll be using another service (Firebase) for that, but then integrating the whole experience in Vue.<\/p>\n\n\n\n\n\n\n\n

Authentication works quite differently on Single Page Applications (SPAs) than it works on sites that reload every page. You don\u2019t have<\/em> to make an SPA with Vue, but we will in this tutorial. <\/p>\n\n\n\n

Here\u2019s the plan. We\u2019ll build a UI for users to log in and the submitted data will be sent to a server to check if the user exists. If yes, we\u2019ll be sent a token. That\u2019s very useful, because it\u2019s going to be used throughout our site  tocheck if the user is still signed in. If no, the user can always sign up. In other words, it can be used in lots of conditional contexts. Beyond that, if we need any information from the server that requires been logged in, the token is sent to the server through the URL so that information can be only sent to logged in users.<\/p>\n\n\n\n

The complete demo of this tutorial is posted on GitHub<\/a> for those that who are comfortable reading through the code. The rest of us can follow through with the article. The starter file is also on GitHub<\/a> so you can follow through as we code together. <\/p>\n\n\n\n

After downloading the repo, you’ll run npm install<\/code> in your terminal. If you\u2019re going to build this application completely on your own, you’ll have to install Vuex<\/a>, Vue Router<\/a>, and axios<\/a>. We’ll also use Firebase<\/a> for this project, so take a moment to set up a free account and create a new project in there.<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

After adding the project to Firebase, go to the authentication section, and set up a sign in method where we would be using the traditional email\/password provider, that’ll be stored on our Firebase servers.<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

After that we’ll then go to the Firebase Auth REST API documentation<\/a> to get our sign up and sign in API endpoints. We\u2019ll need an API key to use those endpoints in our app and it can be found in the Firebase project settings.<\/p>\n\n\n\n

Firebase offers authentication over the SDK, but we’re using the Auth API to demonstrate authentication over any custom back end server.<\/p>\n\n\n\n

In our stater file, we have the sign up form below. We\u2019re keeping things pretty simple here since we\u2019re focusing on learning the concepts.<\/p>\n\n\n\n

<template>\n\u00a0 <div id=\"signup\">\n\u00a0 \u00a0 <div class=\"signup-form\">\n\u00a0 \u00a0 \u00a0 <form @submit.prevent=\"onSubmit\">\n\u00a0 \u00a0 \u00a0 \u00a0 <div class=\"input\">\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <label for=\"email\">Mail<\/label>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <input\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0type=\"email\"\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0id=\"email\"\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0v-model=\"email\">\n\u00a0 \u00a0 \u00a0 \u00a0 <\/div>\n\u00a0 \u00a0 \u00a0 \u00a0 <div class=\"input\">\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <label for=\"name\">Your Name<\/label>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <input\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 type=\"text\"\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 id=\"name\"\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 v-model.number=\"name\">\n\u00a0 \u00a0 \u00a0 \u00a0 <\/div>\n\u00a0 \u00a0 \u00a0 \u00a0 <div class=\"input\">\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <label for=\"password\">Password<\/label>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <input\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 type=\"password\"\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 id=\"password\"\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 v-model=\"password\">\n\u00a0 \u00a0 \u00a0 \u00a0 <\/div>\n\u00a0 \u00a0 \u00a0 \u00a0 <div class=\"submit\">\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <button type=\"submit\">Submit<\/button>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/div>\n\u00a0 \u00a0 \u00a0 <\/form>\n\u00a0 \u00a0 <\/div>\n\u00a0 <\/div>\n<\/template><\/code><\/pre>\n\n\n\n

If we weren\u2019t working with an SPA, we would naturally use axios to send our data inside the script tag like this:<\/p>\n\n\n\n

axios.post('https:\/\/identitytoolkit.googleapis.com\/v1\/account\n\u00a0 s:signUp?key=[API_KEY]', {\n\u00a0 \u00a0 email: authData.email,\n\u00a0 \u00a0 password: authData.password,\n\u00a0 \u00a0 returnSecureToken: true\n\u00a0 })\n\u00a0 .then(res => {\n\u00a0 \u00a0 console.log(res)\n\u00a0 })\n\u00a0 .catch(error => console.log(error)) \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 }\n}<\/code><\/pre>\n\n\n

Sign up and log in<\/h4>\n\n\n

Working with an SPA (using Vue in this case) is very different from the above approach. Instead, we’ll be sending our authorization requests using Vuex<\/a> in our actions in the store.js<\/code> file. We\u2019re doing it this way because we want the entire app to be aware of any change to the user\u2019s authentication status.<\/p>\n\n\n\n

actions: {\n\u00a0 signup ({commit}, authData) {\n\u00a0 \u00a0 axios.post('https:\/\/identitytoolkit.googleapis.com\/v1\/accounts:signUp?key=[API_KEY]', {\n\u00a0 \u00a0 \u00a0 email: authData.email,\n\u00a0 \u00a0 \u00a0 password: authData.password,\n\u00a0 \u00a0 \u00a0 returnSecureToken: true\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .then(res => {\n\u00a0 \u00a0 \u00a0 console.log(res)\n\u00a0 \u00a0 \u00a0 router.push(\"\/dashboard\")\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .catch(error => console.log(error))\n\u00a0 },\n\u00a0 login ({commit}, authData) {\n\u00a0 \u00a0 axios.post(https:\/\/identitytoolkit.googleapis.com\/v1\/accounts:signIn?key=[API_KEY]', {\n\u00a0 \u00a0 \u00a0 email: authData.email,\n\u00a0 \u00a0 \u00a0 password: authData.password,\n\u00a0 \u00a0 \u00a0 returnSecureToken: true\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .then(res => {\n\u00a0 \u00a0 \u00a0 console.log(res)\n\u00a0 \u00a0 \u00a0 router.push(\"\/dashboard\")\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .catch(error => console.log(error))\n\u00a0 }\n}<\/code><\/pre>\n\n\n\n

We can use pretty much the same thing for the sign in method, but using the sign in API endpoint instead. We then dispatch both the sign up and log in from the components, to their respective actions in the store.<\/p>\n\n\n\n

methods : { \n  onSubmit () {\n    const formData = {\n      email : this.email,\n      name : this.name,     \n      password : this.password\n    }\n    this.$store.dispatch('signup', formData)\n    }\n  }\n}<\/code><\/pre>\n\n\n\n

formData<\/code> contains the user\u2019s data.<\/p>\n\n\n\n

methods : {\n  onSubmit () {\n    const formData = {\n      email : this.email,\n      password : this.password\n    }\n    this.$store.dispatch('login', {email: formData.email, password: formData.password})\n  }\n}<\/code><\/pre>\n\n\n\n

We\u2019re taking the authentication data (i.e. the token and the user’s ID) that was received from the sign up\/log in form, and using them as state with Vuex. It’ll initially result as null<\/code>.<\/p>\n\n\n\n

state: {\n\u00a0 idToken: null,\n\u00a0 userId: null,\n\u00a0 user: null\n}<\/code><\/pre>\n\n\n\n

We now create a new method called authUser<\/code> in the mutations that’ll store the data that’s collected from the response. We need to import the router into the store as we’ll need that later.<\/p>\n\n\n\n

import router from '\/router'\n\u2028\nmutations : {\n\u00a0 authUser (state, userData) {\n\u00a0 \u00a0 state.idToken = userData.token\n\u00a0 \u00a0 state.userId = userData.userId\n\u00a0 }\n}<\/code><\/pre>\n\n\n\n

Inside the .then<\/code> block in the signup\/login methods in our actions, we’ll commit our response to the authUser<\/code> mutation just created and save to local storage.<\/p>\n\n\n\n

actions: {\n\u00a0 signup ({commit}, authData) {\n\u00a0 \u00a0 axios.post('https:\/\/identitytoolkit.googleapis.com\/v1\/accounts:signUp?key=[API_KEY]'), {\n\u00a0 \u00a0 \u00a0 email: authData.email,\n\u00a0 \u00a0 \u00a0 password: authData.password,\n\u00a0 \u00a0 \u00a0 returnSecureToken: true\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .then(res => {\n\u00a0 \u00a0 \u00a0 console.log(res)\n\u00a0 \u00a0 \u00a0 commit('authUser', {\n\u00a0 \u00a0 \u00a0 \u00a0 token: res.data.idToken,\n\u00a0 \u00a0 \u00a0 \u00a0 userId: res.data.localId\n\u00a0 \u00a0 \u00a0 })\n\u00a0 \u00a0 \u00a0 localStorage.setItem('token', res.data.idToken)\n\u00a0 \u00a0 \u00a0 localStorage.setItem('userId', res.data.localId)\n\u00a0 \u00a0 \u00a0 router.push(\"\/dashboard\")\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .catch(error => console.log(error))\n\u00a0 },\n\u00a0 login ({commit}, authData) {\n\u00a0 \u00a0 axios.post('https:\/\/identitytoolkit.googleapis.com\/v1\/accounts:signIn?key=[API_KEY]'), {\n\u00a0 \u00a0 \u00a0 email: authData.email,\n\u00a0 \u00a0 \u00a0 password: authData.password,\n\u00a0 \u00a0 \u00a0 returnSecureToken: true\n\u00a0 \u00a0 })\n\u00a0 \u00a0 .then(res => {\n\u00a0 \u00a0 \u00a0 console.log(res)\n\u00a0 \u00a0 \u00a0 commit('authUser', {\n\u00a0 \u00a0 \u00a0 \u00a0 token: res.data.idToken,\n\u00a0 \u00a0 \u00a0 \u00a0 userId: res.data.localId\n\u00a0 \u00a0 \u00a0 })\n\u00a0 \u00a0 \u00a0 \u00a0 localStorage.setItem('token', res.data.idToken)\n\u00a0 \u00a0 \u00a0 \u00a0 localStorage.setItem('userId', res.data.localId)\n\u00a0 \u00a0 \u00a0 \u00a0 router.push(\"\/dashboard\")\n\u00a0 \u00a0 \u00a0 })\n\u00a0 \u00a0 .catch(error => console.log(error))\n\u00a0 }\n}<\/code><\/pre>\n\n\n

Setting up an Auth guard<\/h3>\n\n\n

Now that we have our token stored within the application, we’re going touse this token while setting up our Auth guard. What\u2019s an Auth guard? It protects the dashboard from unauthenticated users access it without tokens.<\/p>\n\n\n\n

First, we’ll go into our route file and import the store. The store is imported because of the token that\u2019ll determine the logged in state of the user.<\/p>\n\n\n\n

import store from '.\/store.js'<\/code><\/pre>\n\n\n\n

Then within our routes array, go to the dashboard path and add the method beforeEnter<\/code> which takes three parameters: to<\/code>, from<\/code> and next<\/code>. Within this method, we’re simply saying that if the tokens are stored (which is automatically done if authenticated), then next<\/code>, meaning it continues with the designated route. Otherwise, we’re leading the unauthenticated user back to the sign up page.<\/p>\n\n\n\n

{\n  path: '\/dashboard',\n  component: DashboardPage,\n  beforeEnter (to, from, next) {\n    if (store.state.idToken) {\n      next()\n    } \n    else {\n      next('\/signin')\n    }\n  }\n}<\/code><\/pre>\n\n\n

Creating the UI state<\/h3>\n\n\n

At this point, we can still see the dashboard in the navigation whether we’re logged in or not,  and that’s not what we want. We have to add another method under the getters called ifAuthenticated<\/code> which checks if the token within our state is null<\/code>, then update the navigation items accordingly.<\/p>\n\n\n\n

getters: {\n\u00a0 user (state) {\n\u00a0 \u00a0 return state.user\n\u00a0 },\n\u00a0 ifAuthenticated (state) {\n\u00a0 \u00a0 return state.idToken !== null\n\u00a0 }\n}<\/code><\/pre>\n\n\n\n

Next, let\u2019s open up the header component and create a method called auth<\/code> inside the computed<\/code> property. That will dispatch to the ifAuthenticated<\/code> getters we just created in the store. ifAuthenticated<\/code> will return false<\/code> if there’s no token, which automatically means auth<\/code> would also be null<\/code>, and vice versa. After that, we add a v-if<\/code> to check if auth<\/code> is null<\/code> or not, determining whether the dashboard option would show in the navigation.<\/p>\n\n\n\n

<template>\n\u00a0 <header id=\"header\">\n\u00a0 \u00a0 <div class=\"logo\">\n\u00a0 \u00a0 \u00a0 <router-link to=\"\/\">Vue Authenticate<\/router-link>\n\u00a0 \u00a0 <\/div>\n\u00a0 \u00a0 <nav>\n\u00a0 \u00a0 \u00a0 <ul>\n\u00a0 \u00a0 \u00a0 \u00a0 <li v-if='auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <router-link to=\"\/dashboard\">Dashboard<\/router-link>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 \u00a0 <li \u00a0v-if='!auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <router-link to=\"\/signup\">Register<\/router-link>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 \u00a0 <li \u00a0v-if='!auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <router-link to=\"\/signin\">Log In<\/router-link>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 <\/ul>\n\u00a0 \u00a0 <\/nav>\n\u00a0 <\/header>\n<\/template>\n<script>\n\u00a0 export default {\n\u00a0 \u00a0 computed: {\n\u00a0 \u00a0 \u00a0 auth () {\n\u00a0 \u00a0 \u00a0 \u00a0 return this.$store.getters.ifAuthenticated\n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 },\n\u00a0 }\n<\/script><\/code><\/pre>\n\n\n

Logging out<\/h3>\n\n\n

What’s an application without a logout button? Let\u2019s create a new mutation called clearAuth<\/code>, which sets both the token and userId<\/code> to null<\/code>.<\/p>\n\n\n\n

mutations: {\n\u00a0 authUser (state, userData) {\n\u00a0 \u00a0 state.idToken = userData.token\n\u00a0 \u00a0 state.userId = userData.userId\n\u00a0 },\n\u00a0 clearAuth (state) {\n\u00a0 \u00a0 state.idToken = null\n\u00a0 \u00a0 state.userId = null\n\u00a0 }\n}<\/code><\/pre>\n\n\n\n

Then, in our logout<\/code> action , we commit to clearAuth<\/code>, delete local storage and add router.replace('\/')<\/code> to properly redirect the user following logout.<\/p>\n\n\n\n

Back to the header component. We have an onLogout<\/code> method that dispatches our logout<\/code> action in the store. We then add a @click<\/code> to the button which calls the to the onLogout<\/code> method as we can see below:<\/p>\n\n\n\n

<template>\n\u00a0 <header id=\"header\">\n\u00a0 \u00a0 <div class=\"logo\">\n\u00a0 \u00a0 \u00a0 <router-link to=\"\/\">Vue Authenticate<\/router-link>\n\u00a0 \u00a0 <\/div>\n\u00a0 \u00a0 <nav>\n\u00a0 \u00a0 \u00a0 <ul>\n\u00a0 \u00a0 \u00a0 \u00a0 <li v-if='auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <router-link to=\"\/dashboard\">Dashboard<\/router-link>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 \u00a0 <li \u00a0v-if='!auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <router-link to=\"\/signup\">Register<\/router-link>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 \u00a0 <li \u00a0v-if='!auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <router-link to=\"\/signin\">Log In<\/router-link>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<li \u00a0v-if='auth'>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <ul @click=\"onLogout\">Log Out<\/ul>\n\u00a0 \u00a0 \u00a0 \u00a0 <\/li>\n\u00a0 \u00a0 \u00a0 <\/ul>\n\u00a0 \u00a0 <\/nav>\n\u00a0 <\/header>\n<\/template>\n<script>\n\u00a0 export default {\n\u00a0 \u00a0 computed: {\n\u00a0 \u00a0 \u00a0 auth () {\n\u00a0 \u00a0 \u00a0 \u00a0 return this.$store.getters.ifAuthenticated\n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 },\n\u00a0 \u00a0 methods: {\n\u00a0 \u00a0 \u00a0 onLogout() {\n\u00a0 \u00a0 \u00a0 \u00a0 this.$store.dispatch('logout')\n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n\u00a0 }\n<\/script><\/code><\/pre>\n\n\n

Auto login? Sure!<\/h3>\n\n\n

We’re almost done with our app. We can sign up, log in, and log out with all the UI changes we just made. But, when we refresh our app, we lose the data and are signed out, having to start all over again because we stored our token and Id in Vuex, which is JavaScript. This means everything in the app gets reloaded in the browser when refreshed. <\/p>\n\n\n\n

What we’ll do is to retrieve the token within our local storage. By doing that, we can have the user’s token in the browser regardless of when we refresh the window, and even auto-login the user as long as the token is still valid.<\/p>\n\n\n\n

Create a new actions method called AutoLogin<\/code>, where we’ll get the token and userId<\/code> from the local storage, only if the user has one. Then we commit our data to the authUser<\/code> method in the mutations.<\/p>\n\n\n\n

actions : {\n\u00a0 AutoLogin ({commit}) {\n\u00a0 \u00a0 const token = localStorage.getItem('token')\n\u00a0 \u00a0 if (!token) {\n\u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 }\n\u00a0 \u00a0 const userId = localStorage.getItem('userId')\n\u00a0 \u00a0 const token = localStorage.getItem('token')\n\u00a0 \u00a0 commit('authUser', {\n\u00a0 \u00a0 \u00a0 idToken: token,\n\u00a0 \u00a0 \u00a0 userId: userId\n\u00a0 \u00a0 })\n\u00a0 }\n}<\/code><\/pre>\n\n\n\n

We then go to our App.vue<\/code> and make a created<\/code> method where we’ll dispatch the autoLogin<\/code> from our store when the app is loaded.<\/p>\n\n\n\n

created () {\n\u00a0 this.$store.dispatch('AutoLogin')\n}<\/code><\/pre>\n\n\n\n

Yay! With that, we’ve successfully implemented authentication within our app and can now deploy using npm run build<\/code>. Check out the live demo<\/a> to see it in action.<\/p>\n\n\n\n

The example site is purely for demonstration purposes. Please do not share real data, like your real email and password, while testing the demo app.<\/p>\n","protected":false},"excerpt":{"rendered":"

Authentication (logging in!) is a crucial part of many websites. Let\u2019s look at how to go about it on a […]<\/p>\n","protected":false},"author":274516,"featured_media":308313,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_share_on_mastodon":"0","_share_on_mastodon_status":"%title% %permalink%"},"categories":[4],"tags":[2232,1073,1079],"class_list":["post-308304","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-articles","tag-authentication","tag-vue","tag-vuex"],"acf":{"show_toc":"No"},"share_on_mastodon":{"url":"","error":""},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/05\/vue-logo-lock.jpg?fit=1200%2C600&ssl=1","jetpack-related-posts":[{"id":292292,"url":"https:\/\/css-tricks.com\/protecting-vue-routes-with-navigation-guards\/","url_meta":{"origin":308304,"position":0},"title":"Protecting Vue Routes with Navigation Guards","author":"Divya Sasidharan","date":"July 11, 2019","format":false,"excerpt":"Authentication is a necessary part of every web application. It is a handy means by which we can personalize experiences and load content specific to a user \u2014 like a logged in state. It can also be used to evaluate permissions, and prevent otherwise private information from being accessed by\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/white-brick-wall.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/white-brick-wall.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/white-brick-wall.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/white-brick-wall.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/white-brick-wall.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":346563,"url":"https:\/\/css-tricks.com\/using-nuxt-and-supabase-for-a-multi-user-blogging-app\/","url_meta":{"origin":308304,"position":1},"title":"Using Nuxt and Supabase for a Multi-User Blogging App","author":"Nader Dabit","date":"August 19, 2021","format":false,"excerpt":"Nuxt is a JavaScript framework that extends the existing functionality of Vue.js with features like server-side rendering, static page generation, file-based routing, and automatic code splitting among other things. I\u2019ve been enjoying using frameworks like Nuxt and Next because they offer not only more features, but better performance and a\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/08\/supabase-nuxt.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/08\/supabase-nuxt.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/08\/supabase-nuxt.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/08\/supabase-nuxt.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/08\/supabase-nuxt.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":298370,"url":"https:\/\/css-tricks.com\/an-early-look-at-the-vue-3-composition-api-in-the-wild\/","url_meta":{"origin":308304,"position":2},"title":"An Early Look at the Vue 3 Composition API in the Wild","author":"Mateusz Rybczonek","date":"November 13, 2019","format":false,"excerpt":"I recently had an opportunity to try the new Vue Composition API in a real project to check where it might be useful and how we could use it in the future. Until now, when we were creating a new component we were using Options API. That API forced us\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/03\/vue-circles.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/03\/vue-circles.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/03\/vue-circles.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/03\/vue-circles.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/03\/vue-circles.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":256347,"url":"https:\/\/css-tricks.com\/firebase-react-part-2-user-authentication\/","url_meta":{"origin":308304,"position":3},"title":"Firebase & React Part 2: User Authentication","author":"Simon Bloom","date":"July 7, 2017","format":false,"excerpt":"Today we'll be adding authentication (via Google Authentication and Firebase) to our Fun Food Friends app, so that only users that are signed in can view who is bringing what to the potluck, as well as be able to contribute their own items. When users are not signed in, they\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":305335,"url":"https:\/\/css-tricks.com\/apis-and-authentication-on-the-jamstack\/","url_meta":{"origin":308304,"position":4},"title":"APIs and Authentication on the Jamstack","author":"Divya Sasidharan","date":"March 31, 2020","format":false,"excerpt":"The first \u201cA\u201d in the Jamstack stands for \u201cAPIs\u201d and is a key contributor to what makes working with static sites so powerful. APIs give developers the freedom to offload complexity and provide avenues for including dynamic functionality to an otherwise static site. Often, accessing an API requires validating the\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/oauth-flow-featured.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/oauth-flow-featured.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/oauth-flow-featured.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/oauth-flow-featured.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/03\/oauth-flow-featured.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":337319,"url":"https:\/\/css-tricks.com\/react-authentication-access-control\/","url_meta":{"origin":308304,"position":5},"title":"React Authentication & Access Control","author":"Tyler Warnock","date":"April 1, 2021","format":false,"excerpt":"Authentication and access control are required for most applications, but they often distract us from building core features. In this article, I\u2019ll cover a straightforward way to add auth and access control in React. Instead of adding a static library that you have to keep up to date or re-research\u2026","rel":"","context":"In "Sponsored"","block_context":{"text":"Sponsored","link":"https:\/\/css-tricks.com\/category\/sponsored\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/react-authentication.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/react-authentication.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/react-authentication.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/react-authentication.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/react-authentication.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/308304","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/274516"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=308304"}],"version-history":[{"count":6,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/308304\/revisions"}],"predecessor-version":[{"id":311256,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/308304\/revisions\/311256"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/308313"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=308304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=308304"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=308304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}