Vue router.push() shows 404 component except browser is reloaded manually - laravel

With Laravel api resources, I have returned a desired path which I intend a user be redirected to once a record is successfully created.
The challenge now is that although it routes properly with Vuefrontend from the address bar on the browser, it loads the wrong component of 404 until I hit the refresh button on the browser. Is there a better way of fixing this without using window.location='path'?
Currently on my router file, I have the following.
import Vue from 'vue';
import VueRouter from 'vue-router';
import viewAsset from "./components/views/assets/viewAsset";
import NotFound from "./components/NotFound";
Vue.use(VueRouter);
export default new VueRouter({
routes: [
{ path: '/asset/:id/details', component: viewAsset, meta: {title: 'Asset Details ' }
},
],
mode: 'history'
})
And i'm using this.$router.push(response.data.links.self ); for the routing, where response.data.links.self is the path returned from the api

Related

Access token not passed in subsequent requests (websanova/vue-auth for Laravel & Vue SPA)

I've been banging my head against the wall for hours now and I'm hoping someone can help me finalize the setup of the websanova/vue-auth library so my Vue SPA can authenticate against my api endpoints.
The point I'm at is that I'm performing a login (this.$auth.login()) in Vue and it's authenticating successfully, but when it attempts to pull the user's info immediately afterwards, that api call fails with a 401 error code. That makes sense because from what I can tell by inspecting the http calls, it doesn't pass a Bearer authentication header in the second request. But my understanding is that if I'm using the bearer driver for vue-auth, passing along the Bearer header is literally it's primary function.
Some environment info:
Laravel 8.13.0
Vue 2.6.12
#websanova/vue-auth#4.1.2 (configured to use axios, not Vue Resource)
Laravel Passport 10.1 (and my api endpoints are guarded by it)
Here's the current state of things:
I know Laravel Passport & the api endpoint authentication is working ok because if I grab the access token that the login call returns and use it to make a manual request to the endpoint that's used to pull the user's info via Postman , it works.
I don't believe CORS is an issue because the front-end and back-end are on the same domain.
I know that vue-auth is installed and at least partially functioning since it does attempt the login. And if I disable the fetchUser parameter, it does appear to attempt to redirect after the successful login.
I've gone over my vue-auth setup over and over based on the Vue 2 examples in the project documentation here and the configs in the 2.x sample app as well as some of the tutorials I followed to get this far like this, and this, and this but I've run out of ideas.
My current theories are:
Maybe I'm not calling or initializing the bearer driver properly so it can do the various calls but isn't attempting to add the bearer token on any http calls(?)
Maybe the login is returning the access token but it's not being stored/captured so when it makes the subsequent call, it can't find it and leaves the header out as a result(?) (I don't see the access token in the cookies, local storage or session storage in my browser)
I'm running on a self-signed SSL cert, not sure if the browser might dislike that(?)
I don't currently have anything in place for handling token refreshes yet. Not sure if that is an issue at this point?
The instructions indicated to use "Vue.router" for the router attribute in the plugins section of the vue-auth options but when I try that, it says it's undefined so that could be a source of trouble. (But I referenced the main VueRouter and it doesn't seem to be throwing any errors)
Here's my vue & vue-auth configuration:
import App from './App.vue';
import Vue from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';
Vue.use(VueAxios, axios);
import VueRouter from 'vue-router';
// From https://websanova.com/docs/vue-auth/guides/startup
// Also tried the other 2.x variation on that page.
// Also tried the ones here with no difference: https://github.com/websanova/vue-auth/blob/master/demos/2.x/src/config/plugins.js
import auth from '#websanova/vue-auth/dist/v2/vue-auth.esm.js';
import driverAuthBearer from '#websanova/vue-auth/dist/drivers/auth/bearer.esm.js';
import driverHttpAxios from '#websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js';
import driverRouterVueRouter from '#websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js';
window.Vue = require('vue');
import {routes} from './routes';
import Vuelidate from 'vuelidate'
Vue.use(VueRouter);
Vue.use(Vuelidate);
const router = new VueRouter({
mode: 'history',
base: '/app/',
routes: routes
});
// From https://github.com/websanova/vue-auth/blob/master/demos/2.x/src/config/plugins.js
Vue.use(auth, {
plugins: {
http: Vue.axios, // Axios
router: router,
},
drivers: {
auth: driverAuthBearer,
http: driverHttpAxios,
router: driverRouterVueRouter,
oauth2: {
}
},
options: {
registerData: {url: '/api/register', method: 'POST', redirect: '/login'},
loginData: {url: '/api/login', method: 'POST', redirect: '', fetchUser: true},
logoutData: {url: '/api/logout', method: 'POST', redirect: '/', makeRequest: true},
fetchData: {url: '/api/users/me', method: 'GET', enabled: true},
refreshData: {url: '/api/refresh', method: 'GET', enabled: true, interval: 30},
rolesKey: 'type',
notFoundRedirect: {name: 'user-account'},
},
});
And here's my login method in my login page:
login() {
// get the redirect object
var redirect = this.$auth.redirect()
var app = this
this.$auth
.login({
data: {
email: app.email,
password: app.password
},
redirect: {name: 'home'},
rememberMe: true,
staySignedIn: true,
fetchUser: true
});
}
If anyone can spot anything that I might've missed, it would be much appreciated!

How do I send CSRFToken in my axios requests using Nuxt and Django on the backend?

I'm using Django Rest as a backend api, and each API call requires a CSRF Token in the headers. In my "Applications" tab in Developer Tools, I clearly have a "csrftoken" value and I somehow need to extract that with each subsequent POST request that my Nuxt application does (using Nuxt/Axios)
My settings.py looks like this:
CORS_ORIGIN_WHITELIST = (
"http://localhost:3000",
"http://127.0.0.1:3000",
)
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
CORS_EXPOSE_HEADERS = ['Content-Type', 'X-CSRFToken']
CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_HTTPONLY = True
I have tried using js-cookies with Cookies.get("csrftoken") which just returns undefined. Is the cookie not accessible because it's set to HTTPONLY`?
What is the recommended step here? Should I create a view in my django backend to generate a CSRF Token, and then before making each request on the frontend, I call this view in my Django app to fetch the token?
E.g
def get_csrf(request):
response = JsonResponse({"detail": "CSRF cookie set"})
response["X-CSRFToken"] = get_token(request)
return response
Not sure how to proceed..
My Nuxt/Axios requests looks something like this:
const response =
await this.$axios.$post("/api/portfolios/", stockData,
{ headers: { "X-CSRFToken": /* Need some value here. */ }
});
I can however get the cookie using nuxtServerInit in my Nuxt Store:
async nuxtServerInit({commit}) {
console.log(this.$cookies.get("csrftoken")) // this works, can store it in some state
},
I can store the value from nuxtServerInit in a Nuxt store. However, whenever I logout, how do I make sure to extract the new csrftoken from the browser? The nuxtServerInit part above only works if I do a page reload, which isn't ideal.
Appreciate any guidance I can get.
Setup axios with default xsrfHeaderName and xsrfCookieName values via nuxt plugin.
When configured, axios will include in request your csrf header with cookie value if it's present in cookies.
in nuxt.config.js include your new plugin
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
'~/plugins/axios',
]
create plugins/axios.js
There is the option to declare as global default config, or for a nuxt instance.
// content of plugins/axios.js
/*
// This is a global config declaration that works on any axios instance,
// meaning that if you just import axios from 'axios' in any place, you will get those.
// This will also work on the axios instance that nuxt creates and injects.
import axios from 'axios'
axios.defaults.xsrfHeaderName = 'x-csrftoken'
axios.defaults.xsrfCookieName = 'csrftoken'
*/
export default function ({ $axios }) {
// This is a nuxt specific instance config, this will work in
// everyplace where nuxt inject axios, like Vue components, and store
$axios.defaults.xsrfHeaderName = 'x-csrftoken'
$axios.defaults.xsrfCookieName = 'csrftoken'
}

"Must provide query string" error with Apollo Client on React and Nexus Graphql Server

I'm starting to work with GraphQL and the new Nexus Framework GraphQL server, which is a great product.
On my server-side, I defined my schema, I can query my database with Prisma and everything runs smoothly. I can query data also from the Nexus GraphQL playground and also with Postman.
Now, I want to make things work on the client-side. I see that Apollo Client is the best solution to integrate React with GraphQL, but I just can't make things work. I read tons of docs but I'm missing something that I can't figure out.
GraphQL and the client part will be hosted on the same server, on separate node applications.
I'm configuring Apollo based on its documentations. The example below is for the new 3.0 Beta Version of Apollo which I'm testing, but the same scenario happens on the last stable version. I believe that I need to do something else to integrate Apollo and Nexus.
Every query returns: "Must Provide Query String".
The same query inside the playground works perfectly.
Here is my basic testing code:
apollo.js:
import { ApolloClient, HttpLink, InMemoryCache } from '#apollo/client'
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: 'http://localhost:4000/graphql',
fetchOptions: {
mode: 'no-cors',
}
})
})
export default client
App.js:
import React from 'react'
import { ApolloProvider } from '#apollo/client';
import client from './database/apollo'
import Home from './components/Home'
const App = () => {
return (
<ApolloProvider client={client}>
<Home />
</ApolloProvider>
)
}
export default App;
Home.js:
import React, { useState, useEffect, useReducer } from 'react'
import { useQuery, gql } from '#apollo/client'
const PUBLICATIONS = gql`
{
albumreviews(last: 1) {
title
}
}
`
const Home = () =>{
const { loading, error, data } = useQuery(PUBLICATIONS)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.albumreviews.map(({ review }) => (
<div>{JSON.parse(review)}</div>
))
}
export default Home
On the client-side: "Error" is displayed.
On the server-side: "Must provide query string"
Believe me, I've tried to adjust the query thousands of times trying to get a different answer.
Could some help me to move forward with this? Should I provide the Nexus schema to the apollo client? What is the better way of doing this?
You should pretty much never use no-cors. Off hand, I'm not sure why that option would cause your request to be malformed, but it will make it impossible for your response to be read anyway. Remove fetchOptions and whitelist your client URL in your CORS configuration on the server-side. CORs usage with Nexus is shown here in the docs.

Redirect routes not redirecting to the correct routes

I'm building a dashboard interface in Vue with Vue-router using history mode. Everything is working fine when you navigate to the individual routes cooresponding to the sections of the dashboard (e.g. '/employees/dashboard/main', '/employees/dashboard/orders/all'). I'm trying to set up some redirects in the web.php file using Route::redirect('/here', '/there'). I want everything to go to my dashboard landing page route: '/employees/dashboard/main'. Some routes properly redirect and some don't depending on if a '/' is at the end of the URI or not.
'/employees' redirects to '/dashboard/main' (incorrect)
'/employees/' redirects to '/employees/dashboard/main' (correct)
'/employees/dashboard' redirects to '/employees/dashboard/main' (correct)
'/employees/dashboard/' redirects to '/employees/dashboard/dashboard/main' (incorrect)
web.php (snippet)
//Employee Routes
//below route was also giving the same result but I left here to show that
//I've also tried it.
//Route::redirect('/employees', '/employees/dashboard/main');
Route::group(['prefix' => 'employees'], function() {
Route::redirect('', 'dashboard/main', 308);
Route::redirect('/', 'dashboard/main', 308);
Route::redirect('/dashboard', 'dashboard/main', 308);
//catch-all route so vue router routes don't throw 404
Route::get('/dashboard/{any}', 'EmployeeController#showDashboard')
->where('any', '.*')
->name('employee.dashboard');
});
employee-dashboard.js (snippet)
const router = new VueRouter({
mode: 'history',
linkActiveClass: 'active',
routes: [
{path: '/employees/dashboard/main', component: Main},
{
path: '/employees/dashboard/orders',
component: Orders,
redirect: '/employees/dashboard/orders/active',
children: [
{path: 'all', component: FilteredOrders},
{path: 'active', component: FilteredOrders},
{path: 'completed', component: FilteredOrders}
]
}
]
});
const dashboard = new Vue({
el: '#dashboard',
router
});
Then in dashboard.blade.php I have my router-links and router-view set up.
Any help will be greatly appreciated. Thanks.
Edit:
What's even more strange is when I comment out all of the Route::redirect entries in web.php, run php artisan route:clear, and restart php artisan serve, then go to /employees, it still redirects me to the wrong route (/dashboard/main).
I've found the cause of the bad redirects. The browser caches redirects and for some reason will use that rather than the updated redirect route in the routes/web.php file. To clear this cache in Firefox: Go into the history menu and right click on one of the pages from your laravel project, then click "Forget about this site". It will now use the updated redirect routes in your routes file.
I've also changed the redirect to: Route::redirect('/employees', '/employees/login'); since I'm using Laravel's Auth scaffolding and have it set up to redirect to the main page of my dashboard after logging in.
Here is where I found this solution:
https://superuser.com/questions/467999/clear-301-redirect-cache-in-firefox#661767

Angular 5 & Go Webservices

Angular 5 as a front end & backend as Golang and written Services in go
When the page is refreshed, the request is sent to the server which results in a page not found 404 error since the request bypasses the router in angular.
Ex: From Routing if we call /login we are able to display a page but if refresh the same it is showing as page not found 404.
Angular5:
const AppRoutes: Routes = [
{ path: '/', component: SignupComponent, pathMatch: 'full' },
{ path: 'login' , component: LoginComponent },
{ path: 'home' , component: VisitsComponent},
{ path: 'createavisit/:id', component: VisitComponent},
];
go:
http.Handle("/", http.FileServer(http.Dir("./angular/dist")))
http.HandleFunc("/register", RegisterHandler)
http.HandleFunc("/log", LoginHandler)
Could someone help me to fix this issue
In app module file where you import routing module add useHash:true parameter. For example: RouterModule.forRoot(routes, {useHash: true})

Resources