Session not working in Laravel API - laravel-5

Usually I save temporary data/array inside session while working with Website (Non API).
Today I want to do the same thing (save temporary data/array inside session) with Laravel API.
So here is my route.
Route::middleware(['auth:api', 'isMember'])->group(function () {
Route::get('createSession', function (){
$a = Session::put('example', 'this is example session.');
return "session created";
});
Route::get('getSession', function () {
return Session::get('example');
});
});
When I visit /api/createSession it return session created, but when I visit /api/getSession it return nothing.
So how do I work with session inside API?
What I think why this not work because API use Token based authentication instead of Session based Authentication, refer to config/auth.php Authentication Guards section.
If work with session inside API is consider as bad practice, What is your suggestion to save temporary data/array inside API for shared hosting?
What I have tried so far is save data/array in Storage::disk(local) but I don't think it best practice.
Thanks in advance.
PS: I will use Session to store temporary data about Cart

Middleware api did not include StartSession middleware, so you can not get the session. Check it here: https://github.com/laravel/laravel/blob/master/app/Http/Kernel.php#L33
You can add middleware "web" to your route or add \Illuminate\Session\Middleware\StartSession::class, to middleware api but I'm not recommended it. APIs should not use session.
Hope that it can help you.

open app/Http/Kernel.php and then , add \Illuminate\Session\Middleware\StartSession::class, on array protected $routeMiddleware and add on protected $middlewareGroups on api

Related

Laravel sessions not saving when called from Postman or Guzzle

I'm experiencing a problem with sessions in Laravel. My project consists about two projects, one an API and another a WebApp. Both with Laravel 5.5.
The problem is that I want to save a session in my API project but it isn't saved. I save the session like this in api.php:
Route::get('test', function () {
session(['data' => "data"]);
session()->save();
});
If I visit: http://mydomain.dev/test through Firefox, I can see the session in the Laravel DebugBar because it has been saved:
If I make a request with Postman to that URL, session doesn't appear in the Laravel DebugBar! It isn't saved.
After some research, I found this question and people say to include in Kernel.php these two lines:
protected $middleware = [
//...
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
];
I have already added those two lines and the problem persists.
The same happens with Guzzle. From my WebApp, I make a GET call to my API. In the method called in the API, I save a session, and when I retrieve the session in another method of the API, I get null because session hasn't been saved!
My suspicion is that Postman and Guzzle problems with sessions are related, and that there's something I'm missing.
My config\session.php files are as default. I know I have as alternative to save sessions in database, but I would prefer to keep it as default, but if I don't have any alternative, I will change my SESSION_DRIVER option from session.php from file to database.
APIs are and should be sessionless/stateless.
They can not handle it.
That's why token based authentications are used.
In order to make you sure about it. Write a route in web.php file and hit it from postman or browser then you will see a session info if any.

Laravel 5.4: how to protect api routes

I have a react app that fetch datas from laravel api defined like so in routes/api.php:
// this is default route provided by laravel out of the box
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
// ItemController provides an index methods that list items with json
Route::resource('items', 'Api\ItemController', array('except' => array('create','edit')));
// this is to store new users
Route::resource('users', 'Api\UserController', array('only' => array('store')));
for example http://example.com/api/items returns the data as intended but it's really insecure since anyone could access it through postman.
How to make those routes only accessible inside the app?
As I'm new to it I don't understand if I need to set up api_token and how?
Do I need to setup Passport?
Is is related to auth:api middleware?
It may sounds really basic but any help or tutorial suggestions would be greatly appreciated
EDIT
End up with a classic session auth. Moved routes inside web.php. Pass csrf token in ajax request. Actually i didn't need a RESTful API. You only need token auth when your API is stateless.
As you are using Laravel 5.4 you can use Passport, but I haven't implemented yet, but i implemented lucadegasperi/oauth2-server-laravel for one of my laravel projects and it was developed in Laravel 5.1
Here is the link to github repository
lucadegasperi/oauth2-server-laravel
Here is the link to the documentation Exrensive Documentation
Just add the package to the composer json and run composer update,the package will get installed to your application , once installed add the providers array class and aliases array class as mentioned in the Laravel 5 installation part of the documentation,
you have to do a small tweak in order to work perfectly cut csrf from $middleware array and paste it into $routeMiddleware array and again run php artisan vendor:publish after publishing the migrations will be created and run the migration php artisan migrate
if you only want to secure api routes for each client like ios, android and web you can implement Client Credentials Grant, or if you need to every user with oauth the you can implement Authorization Server with the Password Grant or some other.,
Never use the client id or other credentials, generating access token in the form, but add it some where in helper and attach it in the request to the api,
Hope this answer helps you.
You could use JWT it's pretty easy to get it to work. You basically generate a token by requesting Username/Password and passing that token in every request that requires authentication, your URL would look like http://example.com/api/items?token=SOME-TOKEN. without a proper token, he doesn't have access do this endpoint.
As for
How to make those routes only accessible inside the app?
If you mean only your app can use these requests, you can't. Basically the API doesn't know who is sending these requests, he can only check if what you are giving is correct and proceed with it if everything is in order. I'd suggest you to have a look at this question

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 :)

Laravel 5.3 Ajax Login Customize Credentials

I am able to login via Ajax in Laravel 5.3
This is easily accomplished by making a post request to the login route with the proper parameters.
However, for my application, I am designing two ways for a user to be logged in - via the traditional email/password combination that Laravel already supports, and via an access code that would be distributed and allow the possessor of said code to login without an email/password combination. There is no "registration" in my app, there is just different levels of authentication.
Anyway, in /vendor/laravel/framework/src/Illuminate/Foundation/Auth I am editing the AuthenticatesUsers.php and understand that this function specifically handles the login attempts:
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->has('remember')
);
}
My question is, how can I change the success of attempt() based on the content of the request?
In other words, if someone is sending an ajax access code it shouldn't be tested against an email/password combination, as it would obviously fail. Similarly, if they are sending an ajax with email/password parameters, it shouldn't be tested against the list of available access codes.
Am I on the right track? Where in Laravel can I go to make the Auth::attempt() contingent on request parameters?
I will not advice to edit a framework file.
You should rather write a middleware to handle identification of the type of authentication user is requesting for, before sending it to the controller. In your middleware,
public function handle($request, Closure $next)
{
// check if the request has access_code
$request->attributes->add(['using_access_code' => $request->has('access_code')]);
return $next($request);
}
And in your controller, you can check for positive test on this request parameter that we newly added (you can of course do this inside controller directly, but I personally like middleware to handle this because there are chances that you may want to add more functionality)
In your controller, if using_access_code is false, proceed with attempt() login, else, retrieve the user using access_code and manually authenticate the user using Auth::login($user). Let me know if you are unclear.

Laravel, can't log a user by id and then redirect him

I'm using Laravel 5.2. I'd like to log a user by his id and then redirect him to the dashboard but it's not working.
I did this:
$result = Auth::loginUsingId($id);
var_dump($result->toArray());
and the result is fine. It returns the object user with all his data.
But after redirecting the user to the dashboard with return redirect()->route('dashboard'); it send me to login page!
I discover then that Auth::user() returns null !
What shall i do?
Thanks
Authentication needs sessions and for sessions to work you need to use the web middleware. So the routes that need working sessions should be defined like this:
Route::group(['middleware' => ['web']], function () {
// Routes that need sessions go here
});
Use $redirectTo as stated in the documentation, if you get into login again Auth wasn't successful, perhaps something related with session or cookies, or just a bad time configuration. Try Auth::loginUsingId($id, true); then.

Resources