1

I have a fully done project made with a Laravel back end and a react front end. The react app is wrapped in the Laravel code, and will be available only after a login and some selections, which are all done in laravel with its views. I want to make the react app as a standalone app, and make the laravel code into an api, served from a server via. an url, such that the react app will work by making requests to the laravel api.

So my first problem is the following: Is there a way to implement API to my laravel code which mimics my allready existing login implementation?

Since my question is pretty broad, I was not sure what code to provide with this question. The code follows the MVC design pattern, so feel free to ask for some parts of the code.

As a slight off-topic question (don't read this if you just want to help with the laravel stuff): The reason I want to decouple the laravel back end and the react front end app, is to wrap the react app in electron to make it an offline app, using the laravel backend. Is this a reasonable approach?

Edit: I found the crux of the problem is how to perform a login "API style" versus the login form laravel provides. So I think I need to implement a login with laravel Passport, retrieving a user with credentials matching the user one would get by logging in through the laravel login form. But the logic in the laravel login form is hard for me to see through, so I could use a helping hand on how to do this.

Below is the code of my login controller, and the associated middleware. Again, tell if you need any more code.

Login controller (from App/http/controllers/auth):

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller 
{
/*
|---------------------------------------------------------------------
| Login Controller
|------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/

use AuthenticatesUsers;

/**
 * Where to redirect users after login.
 *
 * @var string
 */
protected $redirectTo = '/';

/**
 * Create a new controller instance.
 *
 * @return void
 */
public function __construct()
{
    $this->middleware('guest')->except('logout');
}
}

Middleware (from App/http/Kernel.php):

protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware   \AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

Edit-2:

Here is the code for my web.php routes:

<?php

/*
|---------------------------------------------------------------
| Web Routes
|----------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Auth::routes();

Route::get('/', 'HomeController@index')->name('home');

Route::get('/home', 'HomeController@index')->name('home');

Route::get('/setlocale/{locale}', function (Request $request, $locale) {
  if (in_array($locale, \Config::get('app.locales'))) {
    session()->put('locale', $locale);
  }
  return redirect()->back();
});

Route::get('/profile', 'UserController@show')->name('profile');
Route::patch('/profile', 'UserController@update')->name('users.update');

Route::get('/scan', 'HomeController@index')->name('scan.index');
Route::get('/scan/new', 'ScanController@new')->name('scan.new');
Route::get('/scan/{id}', 'ScanController@show')->name('scan.show');
Route::post('/scan', 'ScanController@create')->name('scan.create');
Route::patch('/scan/{id}', 'ScanController@update')->name('scan.update');
Route::delete('/scan/{id}', 'ScanController@destroy')->name('scan.destroy');

// save SCAN JSON
Route::post('/scan/{id}/save', 'ScanController@save')->name('scan.save');

Edit 3:

First thing, when I create the access token, what is stored in /oauth/personal-access-tokens looks like this:

0:
client:
created_at: "2019-01-04 13:00:48"
id: 3
name: "SCAN Personal Access Client"
password_client: false
personal_access_client: true
redirect: "http://localhost"
revoked: false
updated_at: "2019-01-04 13:00:48"
user_id: null
__proto__: Object
client_id: 3
created_at: "2019-01-15 13:52:22"
expires_at: "2020-01-15 13:52:22"
id: "0321b2d622bd7267273225a64cf6f1723cc74b86076831432fb5af4885051c6776bb8ea77c0d7407"
name: "MyApp"
revoked: false
scopes: []
updated_at: "2019-01-15 13:52:22"
user_id: 1
__proto__: Object

See in the first client, made at 13:00:48, the uder_id is null. Is that a problem?

Secondly, here is how I try making a request using axios, using the function login to get an access token (and I do get the access token), and my API is running on localhost:4321

login = async () => {
return axios.post('http://localhost:4321/api/login', {
  grant_type: 'password',
  client_id: 5,
  client_secret: 'd3zuZL6KbBI4DOq4Z7NQkP1ezrAj5GMjgo39',
  email: 'my mail, used to login',
  password: 'my password',
  scope: '',
})

}

async componentDidMount() {
const accessTokenData = await this.login();

var config = {
  headers: {
    Authorization: "bearer " + accessToken
  },
  grant_type: 'password',
  client_id: 'PassGrantClient',
  client_secret: 'd3zuZL6KbBI4zsDOq4Z7NQkP1ezrAj5GMjgo39',
  scope: '',
};

axios.post(
  'http://localhost:4321/api/getInterview',
  {},
  config
).then((response) => {
  console.log(response)
})
}

Where the getInterview route points to the function

public function getInterview()
{
    $user = Auth::user();
    return response()->json($user);
}

which returns 401.As you can see, I'm not sure what to put where :). If you need more code, feel free to ask :).

Richard Jensen
  • 176
  • 1
  • 14

2 Answers2

1

you need to Conversion your Routes/web to Routes/api

and then you can choose between laravel passport API or jwt API to use in your app

(if you chose jwt you would need to create a folder in the controller and name it API and add API\ in your Routes/api example : Route:post::('/example' , 'API\yourcontroller@yourfunction'); )

and for connection react with the api you will need to send the request to you

www.yourdomain.com/api/your api rout

that is all hope this will work for you

edit :

it much easy than you think , while you work with API you don't need "Login controller (from App/http/controllers/auth)" you will need(after adding laravel passport to your project you can find how in the documentation documentaion ) to create your one controller for authentication

example logincontroller :

 public function login(){
    if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
        $user = Auth::user();

        $success['token'] =  $user->createToken('MyApp')-> accessToken;
        return response()->json(['success' => $success],200);
    }
    else{
        return response()->json(['error'=>'Unauthorised'], 401);
    }
}

and for register you can use

public function register(Request $request){
    $validator = Validator::make($request->all(), [
        'name' => 'required',
        'email' => 'required|email',
        'password' => 'required',
        'c_password' => 'required|same:password',
    ]);
    if ($validator->fails()) {
        return response()->json(['error'=>$validator->errors()], 401);
    }
    $input = $request->all();
    $input['password'] = bcrypt($input['password']);
    $user = User::create($input);
    $success['token'] =  $user->createToken('MyApp')-> accessToken;
    $success['name'] =  $user->name;
    return response()->json(['success'=>$success], $this-> successStatus);
}

you need to khnow wen you login with the passport api that will give you the accsses_token not the user data if you want to get the user data then you will need

to create route in your api like this

Route::group(['middleware' => 'auth:api'], function(){
Route::post('details', 'API\LoginController@details');

}

and your controller add the function

public function details()
{
    $user = Auth::user();
    return response()->json(['success' => $user], 200);
} 

and then send accsses_token to the root to get user data

Edite 2 :

If you want to make a route work only after successful login, it very samples you will need to protect that rout with middleware 'auth:api. Example:

Route::group(['middleware' => 'auth:api'], function(){
        Route::post('test', 'API\testController@test');
                Route::get('test2', 'API\testController@test2');
                Route::post('test3', 'API\testController@test3');

}

  • Thank you for your reply, this seems like the way to go. Used most of the morning going through my code and I found out I don't know how laravel authenticate a user logging in. It seems like it is done through the loginController, but I can't figure out exactly what is happening. I will post the code in the OP. – Richard Jensen Jan 03 '19 at 10:47
  • I wanna start by saying thank you so much for the reply, I've come alot further now. – Richard Jensen Jan 04 '19 at 14:35
  • I wanna start by saying thank you so much for the reply, I've come alot further now. That being said, I'm still not sure what to do. I've installed passport, and added in stuff to the code as per the documentation, but still a little lost how to get my old routes to "play together" API routes. I have updated the OP with my web routes, after edit-2. These routes can only be accessed after a succesfull login. How would emulate that with API routes? Again, if I'm asking for too much, feel free to not reply, you've allready been a huge help! – Richard Jensen Jan 04 '19 at 14:47
  • Thanks as usual :). Did your forget so save your edit, or have you not made it yet? – Richard Jensen Jan 08 '19 at 07:45
  • Oh, I may have figured it out. I can make the login method take parameters username and password, and this will access my users in the database! – Richard Jensen Jan 08 '19 at 09:02
  • Oh, by the way. What do you mean when you say "and then send access_token to the root to get user data"? I don't understand :/. – Richard Jensen Jan 08 '19 at 14:12
  • I mean if you want to get user data from login (like id, name ...) you will need to send accsses_token to get it because when you log in you will get only accsses_token and to get user data you will need to send it to get the data, and I make the example in my answer the function I use to get user data after success login is function details() and the root is protected by middleware auth: API I make an example of it in my answer – Karim soubai Jan 09 '19 at 17:49
  • Hey man, just wanna update and say many thanks for your help, it's all working now! Really appreciate your time. – Richard Jensen Jan 10 '19 at 08:38
  • 1
    no problem at all if you need same think in laravel you can always ask I will happy to help you – Karim soubai Jan 10 '19 at 11:49
  • I am so sorry I forget to edit my answer again i will edite now – Karim soubai Jan 10 '19 at 21:10
  • Hi again. I am still confused about how to use the access token. I can get it just fine, but how do I use it to get data? I have tried using [this](https://stackoverflow.com/questions/40988238/sending-the-bearer-token-with-axios), but my problem here is that in my program, I am allready logged in through a laravel login system, and it seems it just uses the logged in user in Auth::user(). – Richard Jensen Jan 17 '19 at 11:28
  • when you run " passport: install " command you get 'Password grant client ('Client ID and Client Secret ) you will need to send them with the access_token and for the problem, you said I don't understand what you mean but from what I understand from your question if you use a laravel login system you will need to change Form action to the URL to your login API pls give more details about your problem so I can help you – Karim soubai Jan 18 '19 at 12:45
  • Okay, I understand. I will update my OP with new questions after Edit 3 :). – Richard Jensen Jan 18 '19 at 14:04
  • grant client_id is wrong you write (client_id: 'PassGrantClient') but the client_id alwayse is number ( 1,2,3,4 .... ) so your client_id shold locke exapmle client_id: ' 21' – Karim soubai Jan 19 '19 at 12:41
0

I think migrating to Laravel 5 and above with the same schema and logic would be helpful, they now have a new route file called api.php, moreover all response would be converted an JSON object to be consumed by the frontend.

If you dont want to migrate to Laravel, just convert all responses to JSON objects

arun
  • 92
  • 1
  • 3