Google Sign-in in vuejs spa and laravel api - laravel

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.

Related

Laravel Jetstream/Sanctum API authentication

I have been working with Laravel since version 5.X up to version 8.X but always use it for backend API (never used blade template), and always pair it with VueJS on the front-end using JWT authentication (also never messed with any other authentication method).
Now with Laravel 9 and Vue 3, Im trying to use native Laravel Jetstream that uses SANCTUM and Vue+Inertia JS, and I'm quite lost with the authentication process. with JWT method, once the user succesfully login on the browser, all api request to Laravel will be authenticated using Authoraziation header. but this seems a different case with Sanctum.
After deploying and installing Jetstream and completed all the set-up. I created a user and loggedin with that user details. and I notice few things, there is a default API route
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
when I tried to directly access my.domain/api/user I notice it was redirected to GET /login
then redirected again to GET /dashboard
I then created a test api route using below
Route::get('test', function( Request $req) {
dd( [
'test' => $req->all(),
'user' => auth()->user(),
'request' => $req
] );
});
and I notice this request is not authenticated even when the cookies is present on the request as Im when I'm alraedy logged-in on the same browser, the auth()->user() is null.
I tried adding auth:sanctum middleware
Route::middleware('auth:sanctum')->get('test', function( Request $req) {
dd( [
'test' => $req->all(),
'user' => auth()->user(),
'request' => $req
] );
});
but having sanctum middle behave the same as the api/user where if i open api/test directly on the browser, it gets redirected to GET /login then redirected again to GET /dashboard and I'm quite lost at this point. I tried reading the docs and it says I have to do a separate authentication for this that would issue an API token and I was thinking I might better be going back with using JWT auth as it seems a lot easier to deal with.
So my question is; How can I authenticate an API end-point without having to redirect it to /login then /dashboard if the user is already logged in on my application using default sanctum authentication.
My goal is just to simply create /api/test that will be automatically authenticated if user already loggedin on the same browser and return the data I set on its return value and not doing any redirects.
Appreciate any help
I have got the same issue with laravel8
Jetstream and inertia vue3.
Am looking for the solution since 3 days posting messages on discord, searching on YouTube and more but nothing.
When i make an api call from your SPA to laravel, i got UNAUTHENTICATED response.
on postman you need put
headers
Accept = application/json
this tells your application know how works with Json
and go stop redirect to "Login"

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.

Protecting API endpoints of a public contact formular

I'd like to do the following:
My website is designed as Vue SPA, which performs requests to an Laravel-powered API. This API includes a POST-Route that allows to submit the content of a contact formular.
/*Contact Routes*/
Route::group(['prefix' => 'contact'], function ($router) {
/*Send*/
Route::post('/send', 'ContactApiController#send')
->name('api.contact.send');
});
Now I'd like to protect this route, so only requests that are submitted from the SPA are allowed, otherwise I guess I'd need to handle a lot of spam once somebody figures out that it's enough to create simple post requests to the API endpoint.
There's no user auth planned on that site at the moment, so I think that Laravel airlock does not work in this scenario.
My question: How can I protect my routes from being accessed externally?

Why does one Route fail and the other work?

I am using Laravel to serve both my website and a stateless API. I use Passport with a token set in the cookie to Authenticate the API, this is handled by Passport.
I make calls to the API using axios within vue.js
I was getting an issue with an API call that was returning Unauthorized, all other requests were fine, by playing around I have arrived at the finding that
this.$axios.get('session/'+this.session+'/posts')
.then(response => { console.log(response.data); });
Route::get('/session/{code}/posts' , 'PostController#posts');
works; whereas
this.$axios.get('session/posts')
.then(response => { console.log(response.data); });
Route::get('/session/posts' , 'PostController#posts');
does not (returns 401 Unauthorized).
In the first example the $code value is simply an obfuscated ID and is not related to authentication, it is a string of characters. Also, session refers to an internal Application object and is not related to the php session at all.
This is in my Routes service provider:
Route::prefix('api')
->middleware('auth:api')
->namespace($this->namespace.'\API')
->group(base_path('routes/api.php'));
This sets a token in a cookie (laravel_token by default), and uses that to authenticate.
Other routes are successfully authenticating through this, when I add the variable to the route, it works!
Can anyone explain to me why the second version gives an Unauthorized response?
It appears to be the auth:api guard that makes this distinction, but I don't know where in the Laravel framework the actual check() code is.
Kindly check if your routes where a part of a prefix that has the auth:guard api activated. whereas you need to send api generated token to gain authorization.

How to authenticate API requests in Laravel?

I am currently building some sort of posts based web application using Laravel 5(.4). I have decided to load asynchronously the comment section for each post(and refresh it periodically). After some research I have decided to write a small integrated REST API (using the api routes of Laravel) that should answer to the requests made through AJAX.
However, I am facing the problem if authenticating the incoming requests. Take for example a request to post some comment. How exactly would you recommend to do that?
If you are making AJAX requests from browser and you are signed in then you don't need to use Laravel Passport tokens.
You can define certain routes which will be using web,auth middleware on requests like webapi/comments/get like this.
Route::group(['middleware' => ['web','auth]], function () {
Route::get('webapi/comments/get', 'CommentsController#get');
}
And use Auth Facade as you do in web request i.e Auth::check(), Auth::user() etc. and return the data in JSON like this.
class CommentsController extends Controller
{
public function get(Request $request)
{
if($request->acceptsJson()){
$data = array();
// add data
return response()->json([
"data"=> $data,
"status" => true
]);
}else{
return abort(404);
}
}
}
You can also send Accept header in AJAX request as application/json and in controller check if request $request->acceptsJson() and make your decision to show content when url is loaded from browser address bar or requested as AJAX.
Laravel Passport token are useful where there is no session and cookies are managed.
hope this helps :)
"Passport includes an authentication guard that will validate access tokens on incoming requests. Once you have configured the api guard to use the passport driver, you only need to specify the auth:api middleware on any routes that require a valid access token" - from the Laraven Documentation.
Apparently I have to configure passport, and after that configure the auth:api middleware to use the passport driver. Correct me if I'm wrong, please :)

Resources