I am a bit confused, I have a web application having a login, Register, Logout. Some dashboard views etc(CRUD), I want to make an api for this application too.
Like an api which third party will use, Can update records, Can delete records etc.
Actually there should be some way which can be use by mobile app for CRUD.
I know we have that routes/api.php, But i am pretty confused that when to use it. Please explain the scenario, I am blank.
Update:
Scenario
Application having views, authentication system etc, How an android app will be able to perform CRUD operations on the same application ?
1.web routing uses session state, CSRF protection. does it mean api routing not using session state, CSRF protection?
All it possible but not required. You still can using sessions etc, but this is a REST principles violation.
2.laravel 5.3 uses seperate web and api routing, is there any advantages ?
It's just for your convenience. In Laravel 5.2 you need specify middleware for routes like ['web'] or ['api'] but it doesn't required anymore. In 5.3 routes stored in separated files and specify routes middleware not required.
If you are specifying routes in api.php, you will need to use the auth:api middleware. For example:
Route::group(['middleware' => ['auth:api']], function () {
Route::get('/test', function (Request $request) {
return response()->json(['name' => 'test']);
});
});
Notes about Token auth and Laravel 5.3:
If you've setup laravel's default auth system, you will also need to add a column for api_token to the user table. If you are using DB seeders, you might want to add something like:
$table->char('api_token', 60)->nullable();
to your users table seeder. Alternatively just add the column manually and fill that column with a random 60-char key.
When making the request, you can add the api_token as a URL/Querystring parameter like so:
domain.com/api/test?api_token=[your 60 char key].
You can also send the key as a header (if using Postman or similar), i.e: Header: Authorization, Value: Bearer [your 60 char key].
I order to get a useful error if the token is incorrect, also send the following header with all requests:
Header: Accept, Value: application/json. This allows the expectsJson() check in the unauthenticated() function inside App/Exceptions/Handler.php to work correctly.
Related
Does Laravel Passport support having permissions on routes, methods, and a number of requests? e.g., the user can only send GET request, or the user can only send 50 requests for the special route, or the user only has access to special routes.
If not, do you know any package in laravel or other PHP frameworks that provide such facilities for API authentication and authorization?
For this you need to make use of the middleware throttle.
for example:
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
...
}
I'm new to the Laravel API world. I want to make a simple Laravel application than returns some stuff in json format. I don't want it to be accessible to anyone with the url link though. I want to allow the access only by one API key. Is it possible? Or every user must have a unique key? And how can it be done?
yes possible.
You have to have api_token field in users table and also add middleware in your api routes. api.php
Schema::table('users', function ($table) {
$table->string('api_token', 80)->after('password')
->unique()
->nullable()
->default(null);
});
middleware in api routes (api.php):
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
You can define custom api guards for your api as well, for example if you have two tables called doctor and patient, you will have two tables and for both users you will be need unique api_token, you can define those custom api guards in your config/auth.php
see here: https://laravel.com/docs/5.8/api-authentication
Yes, it is absolutely possible. We do not know your application requirements, however if you wish only to return some stuff and therefore you have no need for identifying which user did what, there is no reason to go with key per user as another answer suggested.
For example, you can put your key in .env
API_KEY=yourkey
And then, simply add middleware to api routes, which will first check, if there is a proper ApiKey passed within the request.
You can pass your env variable to any config file and then call config('yourConfigFile.apiKey') anywhere in your app.
For some simple scenarios this approach is 100% sufficient. Take into consideration who will have access to this key and how it will be passed. If there will be one global key, and your api consumer will simply use ajax without proxing it via server, your api key will be exposed and everyone will be able to grab it and use it anywhere.
If that is the case, you can still avoid creating key per user – just specify list of allowed domains which can call your API and then check key. It all can be checked within middleware.
Like I said, know your requirements/use cases and then make a decision :-)
I'm new to laravel and making a web service that can function without javascript (if a user has it disabled or something.)
But it would be a better user experience to be able to perform certain actions without refreshing the whole page. I'd like to be able to say, send a form without reloading the page, or refresh notifications.
The options I can think of are:
1) Send the ajax to the same route as the pure html form, but with an extra variable and make my laravel respond with json when that variable is detected
2) Use the API route? Will this detect the currently logged in user?
3) Make new routes for everything ajax, even though they function the same as my current routes (aside from returning a view)
Also, does the CSRF token work multiple times in a row, or do I need to disable that to handle multiple ajax form posts in a row without page refreshes?
I recommend keeping the routes separate, both to prevent weird caching bugs and for your own sanity as the code changes over time.
Laravel is set up out of the box to let you define web routes in routes/web.php and api routes in routes/api.php. Routes defined in your api.php file will be available at /api/* by default. It's much easier to manage changing the application this way, rather than trying to make your controllers do both views and api responses.
With Laravel Passport, your API routes can detect the currently logged in user via the auth:api middleware when combined with adding the Laravel\Passport\Http\Middleware\CreateFreshApiToken to your web middleware group.
https://laravel.com/docs/5.7/passport#consuming-your-api-with-javascript
An easy way to manage the duplicated controllers (one for web and one for api) is to put Api controllers in their own namespace, with php artisan make:controller Api/FooController. You can even set up your Api routes to look for controllers in this namespace by default by editing RouteServiceProvider.php.
How do I authenticate an user to a channel with a custom auth method?
For example, in my app I use a token auth (stored in the db for each user) for my API, passed via header and read by a custom middleware.
How do I control the access with these custom auth methods for channels? How would be the client and server side? I am using socket.io and the Laravel docs are quite unclear of how auth methods works for sockets.
USE CASE:
I have users stored in DB with default Laravel migration. However, how my app is just the API, it is stateless, then, rather than using remember_token to store session tokens, I use it to store an unique authentication token, generated in the login endpoint.
Every endpoint of the API, the request pass through a middleware, where the user is retrieved by the token present in the headers
$token = Request::header('X-token');
$request->user = User::findByToken($token);
return $next($request);
Now the question comes in. Laravel docs isn't much clear on how private channels works.
How would a broadcast client pass the mentioned token and get authorized to join a given channel?
The Laravel documentation on broadcasting is pretty comprehensive about this, although it doesn't go into minute detail on client libraries that it doesn't support out of the box.
In this case, you're wanting the section on authorizing channels. From the docs:
In the BroadcastServiceProvider included with your Laravel application, you will see a call to the Broadcast::routes method. This method will register the /broadcasting/auth route to handle authorization requests
When defining broadcast routes, the currently authenticated user is passed automatically as a parameter. Since you're wanting to change the authentication mechanism ahead of the broadcast route definition so that the correct user is passed along, your broadcast client would pass along the token (however you like - HTTP header, URL parameter, POST data, etc.) and then you would customise the /broadcasting/auth route to parse that data and use it to authenticate the user. From there you would use the standard Broadcast::channel() definitions to ensure that the authenticated user is also an authorized user on that channel.
As per the documentation, Broadcast::routes() takes an optional array of $attributes for it to use the web middleware. From the source:
$attributes = $attributes ?: ['middleware' => ['web']];
So if you wish, you may change the middleware authentication to 'api' by passing it to the Broadcast::routes() call (or any other standard route parameters).
Since the route is already created for you, if you want to customise it at a lower level that route functions/middleware then you would need to change the auth() method on whichever BroadcastProvider you're using. More specifically, when the route is set up, it calls the authenticate() method on the BroadcastController, which in turn simply calls the auth() method on the Broadcast facade. The facade would then call whichever provider you're using - there are a few providers defined out of the box which should give you a good starting point if you want to write your own. That being said, as long as you don't have a problem with the provider itself, it's probably easier to just write your own middleware and pass that to Broadcast::routes() as an attribute if you need something particular with your authentication (if it differs from the api authentication middleware).
As an extra, since you've tagged this with socket.io, you may also want to read up on Laravel Echo. There's also a section on talking to socket.io specifically in the broadcasting introduction.
On top of Leith's answer, those scratching head and wondering why creating a custom middleware and using it in BroadcastServiceProvider.php would throw back an error.
public function boot()
{
Broadcast::routes(['middleware' => ['custom.middleware']]);
require base_path('routes/channels.php');
}
Inside Broadcaster.php there is a method called retrieveUser() which should return $request->user() as a result of successful authentication from within your custom middleware.
In my case, I was trying to pass access token to API's custom middleware; and once authenticating the user, I simply passed on my original request return $next($request)
For the above code to work, I had to fetch the user model by access token and then merge it to the original request like so
$request->merge(['user' => $user ]);
$request->setUserResolver(function () use ($user) {
return $user;
});
return $next($request);
So now retrieveUser() method from Broadcaster.php is able to retrieve the authenticated user with return $request->user() command, and it gets passed to Broadcast::channel method as a first parameter
Broadcast::channel('private-channel-name', function ($user) {
// if you get here, you've been authenticated (within a custom middleware)
return true;
});
I am using Laravel Passport (auth:api), all works well however I've came with the idea to log record user requests on a specific route.
When an GET request is made to /movie/65 I would like to store in movie_view the following data: user_id, movie_id (if the user is logged in)
However in my controller I am unable to call $request->user() without setting auth:api middleware.
What is the best practice you recommend to achieve this?
Default Auth Type should be set to 'api' in config/auth.php
Source: https://laracasts.com/discuss/channels/general-discussion/optional-authentication-for-api?page=0 (it was very hard to find)
Best way to do this is:
if (\Auth::guard('api')->check()) {
$user = \Auth::guard('api')->user();
}
you have to setup the guard to 'api', the default one is 'web'.
You can create a custom middleware as suggested here -- https://laracasts.com/discuss/channels/laravel/how-to-handle-route-with-optional-authentication. Then apply api guard to it. Let say you assign that custom middleware as auth.optional in Kernel.php, then you can use that middleware as auth.optional:api (with that api guard). Then you can access user thru $request->user() in your case above.