blocked by CORS policy ionic to laravel - ajax

Hello I created an ionic project and I am posting values via ajax to laravel backend (laravell is hosted by MAMP on the background), Whenever I am trying it by postman it's working correctly with a code 200
But whenever I am trying it with my ionic project the code is here
function submitAxiosFormPost(e: React.FormEvent<HTMLInputElement>) {
//? e: React.FormEvent<HTMLInputElement>
// e.preventDefault();
axios.post('http://localhost:8888/api/register', {
name: username,
email: email,
password: password,
password_confirmation: passwordConfirm
})
.then(function (response) {
console.log(response);
window.localStorage.setItem('profile', JSON.stringify(response.data.user));
window.localStorage.setItem('token', JSON.stringify(response.data.access_token));
})
.catch(function (error) {
console.log(error);
// console.log("ERRRR:: ", error.response.data);
});
// name:Nairi7,
// email:hnairiareg7#gmail.com,
// password:Nairi7,
// password_confirmation:Nairi7,
console.log(`Username: ${username}\nEmail: ${email}\nPassword: ${password}\nPasswordConfirm: ${passwordConfirm}`);
}
it's bringing this error

Your Ionic code isn't the problem here. Rather, it's your backend.
The problem has to do with web browsers limiting access to servers with CORS enabled. Web browsers only allow requests to web servers with CORS enabled for security reasons, so malicious sites do not read your data. Below is a link from Mozilla that talks more about CORS:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
I'm not 100% sure what your backend code is, as I'm not familiar with Laravel, so I can't guide you on how to enable CORS for your backend. However, I'm attaching a link which has instructions on enabling CORS for whatever your backend may be (I think Laravel uses PHP, so you might want to check that):
https://enable-cors.org/server.html
Once you enable CORS on your backend, you should be good to go.

You should enable cors on your laravel backend. You may do it manually or use a package like this one https://github.com/fruitcake/laravel-cors

Related

Vue cookie-based authentication in Laravel

From reading the Laravel docs, it appears that when using Sanctum Vue will just use the cookie-based authentication.
I was trying to move an existing app (with login done using Livewire) to Vue, but calls direct to my first api endpoint were redirecting to the login page.
So I created a clean installation of Larvel, installed Breeze (with Inertia), then Sanctum, published the config etc.
But when I login and then visit my test endpoint (which just returns 200 Ok), it redirects to the login page (which, because I am logged in, redirects to the Breeze dashboard).
Do I need to do anything manually for my endpoint, guarded by auth:sanctum, to pass authentication?
Update
I've set axios.defaults.withCredentials, and it's returning 401 Unauthorized. My app.js:
axios.defaults.withCredentials = true;
axios.get('/api/test')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
First ensure that your application's CORS configuration is returning the Access-Control-Allow-Credentials header with a value of True. This may be accomplished by setting the supports_credentials option within your application's config/cors.php configuration file to true.
Then, if you are using axios, you should enable the withCredentials option on your axios instance:
axios.get('some api url', {withCredentials: true});
or globally:
axios.defaults.withCredentials = true;
If you are not using Axios to make HTTP requests from your frontend, you should perform the equivalent configuration on your own HTTP client.
Laravel Docs Reference.
If you are using Postman to test your api, here is a smart implementation of sanctum authentication requests. Basically you have to get the sanctum cookie first, and then send the cookie on XSRF-TOKEN header.

Chrome not allowing Set-Cookie even from the same (sub)domain

Here is my configuration:
SERVER
Laravel 8 application that uses Sanctum to provide access to REST API. It is configured to run on http://b8/
CLIENT
A separate Vue CLI 3.0 SPA that connects to the API using session-based cookie authentication method. I have configured Vue CLI Serve to run it at http://app.b8/.
PROBLEM
Chrome does not allow Set-Cookie operation even when both server and client are on the same domain. After going through several posts and articles, I have successfully run it in Postman, but the real Vue application that runs in the browser can't set Sanctum cookie and thus cannot login.
Here is my configuration:
.env
SESSION_DRIVER=cookie
SESSION_DOMAIN=.b8
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:8080,127.0.0.1,127.0.0.1:8000,::1,b8,app.b8,app.b8:8080
vue.config.js
...
devServer: {
proxy: "http://b8/api/v1",
host: "app.b8"
},
Login function in Vue application
async login(context, credentials) {
axios.get('http://b8/sanctum/csrf-cookie').then(response => {
axios.post('http://b8/login', credentials).then(response2 => {
//successfully logged in.
});
});
},
Error msg
The outer call for /sanctum/csrf-cookie route returns successfully and brings Sanctum cookie. However, Chrome thinks that the cookie is invalid for the current domain and therefore doesn't set it. Here is the Dev Tools pane's Cookies tab after the Sanctum token call returns (tooltip showing Chrome's complaint):
Since the cookie is not set, the following login call fails with a 419 error.
What am I missing here?
Finally got it working. For any future reader, here are the things:
The first mistake that I was doing was to use a single word host name. It looks like Chrome (or Sanctum, not sure) wants you to have at least one period in the host name. So I changed it from b8 to b8.cod.
You should keep same_site attribute set to lax. none is a rather dangerous value. Chrome now shows none as a potential issue.
SESSION_DOMAIN should be set to .b8.cod with a leading period to support front-end subdomain, as correctly suggested by the documentation.
All other things should be done as suggested in the question. axios must use withCredentials set to true.
I've recently set up the exact same thing (Laravel 8 backend with Sanctum + separate Vue Frontend) and it's working.
Your server side setup looks good. Please double-check that the frontend's IP is actually included in your SANCTUM_STATEFUL_DOMAINS - that caused the 419 error for me sometimes.
On the Vue side, make sure to that you enable the withCredentials in your axios instance, e.g.
const baseDomain = "http://localhost"
const baseURL = `${baseDomain}/api`
export default axios.create({
baseURL,
withCredentials: true,
})
If the provided suggestion does not help, I can further extend my answer by showing you more of my working backend code.

How to log in from a single page react app to Laravel 7.x on another domain?

I have a single page create-react-app running on localhost:3000 and I want to log in to a laravel 7.x instance running on myapp.loc (vhost).
Eventually I would like a single page running on app.mysite.com with laravel running on api.mysite.com.
I'm able to log in to my laravel instance directly from myapp.loc. I've installed Laravel passport and the scaffolding, etc and can create Client IDs and Secrets, but I'm unsure if they are needed and if so, how to use them.
What I am unsure of and cannot find any documentation for, is how to log in to laraval from my SPA (running on localhost:3000). I have set my CORS headers and can connect requests that don't require auth, but I don't know how to log in or structure auth requests once logged in.
I can't find any documentation on axios.post / get requests with a focus on logging in from another domain and maintain user-based access.
Since I don't know enough to ask a concise question, there are three layers that I feel like I should be searching for an answer.
Is it possible for laravel to act as the backend for my single page app from another domain?
If so, are there documented, best practices / well worn paths for accomplishing this?
If so, what would a sample axios login and subsequent session call look like? (e.g. payload and header shape)
Yes you can, I suggest to use https://laravel.com/docs/7.x/sanctum instead of passport because is easier to setup and it was created especially for this scenario.
You need to configure CORS using the official Laravel Package https://github.com/fruitcake/laravel-cors this way you will open Laravel's CORS to be able to reach it from anywhere localhost, or any domain that you can set up into allowed_origins. inside the cors.php config file according to the documentation of the package.
After configuring Sanctum/Passport and ensuring you are generating the required token for your SPA using the createToken method described in Sanctum or Passport docs, you have to save the token to connect to your protected endpoints however they recommend to use cookie SPA based authentication but that's not strictly necessary.
Create an API Service
In this example I will create an API Service to encapsulate API calls
import axios from 'axios';
const URI = 'https://yourlaravel.api/api/';
axios.defaults.headers.common = { Accept: 'application/json', 'Content-Type': 'application/json' };
const ApiInstance = axios.create();
const API = {
login: (user) => {
return ApiInstance.post(`${URI}login`, user);
},
getUser: () => {
return ApiInstance.get(`${URI}user`);
},
setUser: (user) => {
return ApiInstance.post(`${URI}user`, user);
},
};
Send A Login Request to your login endpoint and save the token
import API;
API.login({email:'mail#domain.com',password:'32323'})
.then(response=>{
//save the token
//response.data.accessToken
})
Fetch data from your protected endpoints using the token
//Set the default authorization header when you have an access token
axios.defaults.headers.common = {'Authorization': `Bearer ${token}`}
//Get your data
API.getUser().then(response=>{
//response.data
})
//Post something
API.setUser({user:'Os'}).then(response=>{
//response.data
})
All those things are possible, you just need to set up cors and you are good to go. For auth you can use passport or your own custom app key setup, it all depends on what you are trying to achieve. I suggest reading up about RESTfull apis, that would be a good start.
In order to perform a handshake between FE and BE on FE you would have a login form submission of which will send e request to BE (backend api) and if login is success you send back a key which then FE should store. Any future requests from FE should append that key in the header to gain access to authorised areas.
There should be plenty of information on this subject (RESTfull Api & Token authentication) on google.

How to Connect Vue.js App to Laravel REST API After Heroku Deployment

I have a front-end application (Vue.js). I have my own REST API (Laravel). I want my Vue.js app to fetch my data from the REST API. Both apps have been deployed to Heroku and each has their own domains.
Locally, in my Vue.js app, I just had this following code snippet to connect to my REST API:
mounted() {
fetch('http://127.0.0.1:8000/api/testdata', {
method: 'get'
})
.then((response) => {
return response.json()
})
// 'jsonData' refers to the json parsed response
.then((jsonData) => {
this.testData = jsonData.data
})
Since both apps have now been deployed, this obviously doesn't work now. I was wondering what I would have to put inside the fetch() method, now that both apps are on the web.
To view my API data locally with Postman, I can just enter this URL in the 'GET' search: http://127.0.0.1:8000/api/test_data.
Now, I'm not sure what I have to enter to see my deployed API data. I've tried this: https://pure-mountain-87762.herokuapp.com/api/test_data and this: https://pure-mountain-87762.herokuapp.com/test_data.
If I know what to put in Postman to view my data, then I should know what to put in my fetch() method (in theory), since the URL's are the same locally.
Also, does anyone know if there would be anything else to configure after this step has been completed?
Thank you
Yes you add a normal domain url to make requests. It will be Your-app-name.herokuapp.com
Check out if you need CORS allowed methods on your backend

Google Sign-in in vuejs spa and laravel api

I have a single page application with vue.js that uses Laravel 5.5 as its api. I want to add google sign-in to it but I am confused as where to start. I have used laravel socialite before to add google sign-in but that was for pure laravel application and not a laravel api.
Can anyone point to to some resources I can read. Is there a package like socialite for this, Is there a way to use socialite to use in this case as well.
Take a look at hellojs
Hellojs makes it easy. Allows you to open a popup for login with the social provider and returns an access token. then you use the access token in your backend to get the user.
so your js would look something like this
hello
.login(network)
.then(
() => {
const authRes = hello(network).getAuthResponse();
axios
.get('api/link/to/sociak/callback',{
params:{
access_token : authRes.access_token,
provider: network
}
})
.then((response) => {console.log(response.data.token)})})
.catch((error) => {console.log(error.response.data)})
},
(e) => {
console.log(e)
}
)
and in your controller you handle it like ..
public function handleProviderCallback(Request $request)
{
$s_user = Socialite::with($request->provider)->stateless()->userFromToken($request->access_token);
//your logic here...
}
Hope it makes it clearer for you. I was just struggling with this and hello js made my life simple
In adition to the previous answer, i used vue-hellojs to add the goolgle's authentication window and get a token (with 'email, profile' scope).
Then send it to the laravel backend (with google socialite provider and CORS installed) who check if there is a user with that email and respond with a laravel jwt-token to the vue SPA as login do.

Resources