Laravel: AppServiceProvider to register an API Key? - laravel

I'm pretty new to Larvel, so apologies in advance for what I assume is a trivial question.
I'm building a store page using Stripe as my payment processor, and their PHP library requires users to register an API key.
Up to this point, I have been setting my API key in the first line of my Controller that creates the checkout session. This seems unnatural to me, and I thought that there would be a better way to "globally" set this API key upon the application boot up.
I then came across the AppServiceProvider, which I understand can be used to perform tasks on startup. I am now setting my API key in it's register() function, like so:
public function register() {
\Stripe\Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
}
This works but I am wondering if this is normal and best-practice. The Laravel documentation mentions that this is a good place for registering event listeners or even routes, but doesn't mention anything similar to API keys or setting up the registration for third-party libraries.
Thanks in advance!

One suggestion is dont call env anywhere in your code other than config file.Better create config file in config folder.
For example create a file called stripe.php in config folder
<?php
return [
'stripe_secret_key'=>env('STRIPE_SECRET_KEY')
];
Then you can access
\Stripe\Stripe::setApiKey(config('stripe.stripe_secret_key'));
This helps when you cache config.If you run php artisan config:cache then it wont call env
As per documentation
If you execute the config:cache command during your deployment
process, you should be sure that you are only calling the env function
from within your configuration files. Once the configuration has been
cached, the .env file will not be loaded and all calls to the env
function will return null.
Ref: https://laravel.com/docs/8.x/helpers#method-env
difference between register and boot method
“After all providers have been registered, they are “booted”. This
will fire the boot method on each provider. A common mistake when
using service providers is attempting to use the services provided by
another provider in the register method. Since, within the register
method, we have no gurantee all other providers have been loaded, the
service you are trying to use may not be available yet. So, service
provider code that uses other services should always live in the boot
method. The register method should only be used for, you guessed it,
registering services with the container. Within the boot method, you
may do whatever you like: register event listeners, include a routes
file, register filters, or anything else you can imagine.”
So the register one is just for binding. The boot one is to actually
trigger something to happen.
Ref: https://laracasts.com/discuss/channels/general-discussion/difference-between-boot-and-register-method

Related

How to attach middleware to an existing named route from a package in laravel 5?

I'm trying to extend an existing application without modifying its source code.
The application has a named route called wizard-add.
Is there a way to register \MyPackage\MyMiddleware with the existing route?
I tried attaching it via Route::getRoutes()->getByName('wizard-add')->middleware(\MyPackage\MyMiddleware::class); but since packages are registered before the routes are read, Route::getRoutes() returns an empty collection.
Thank you!
Since I didn't find a way to solve this, I extended the app's controllers and put my logic inside.
namespace MyPackage\Controllers;
use App\Controllers\WizardController;
class MyPackageWizardController extends WizardController { ... }
and then in my service provider's register() method:
$this->app->bind(WizardController::class, MyPackageWizardController::class);
So everytime the app attempts to instantiate WizardController, it instantiates MyPackageWizardController instead. I don't know if there are any drawbacks but so far this has been working perfectly for me.

Is it possible to create a second Laravel "api route" with a separate API KEY?

I'm new to Laravel and I am handed an existing application that is composed of two parts:
1 - An admin backend built on Laravel and uses Vueify
2 - The frontend website built on next.js and uses react components
The admin part communicates with Laravel using the "web routes" but also uses the "api routes" as well since the vue components make AJAX requests using those "api routes".
I am now tasked with "connecting" the frontend part to the laravel app. The frontend part will be using AJAX as well to communicate with laravel but I was told I should not use the same "api route" that is used by the admin backend because that has a lot more privileges that should not be accessible by the frontend. Basically it's a security risk and that I should somehow separate the two.
I'm not actually sure which term to use.. I initially thought it was called "channel" but I see that channel is one of the 4 "ways" of connecting to laravel (the other 3 being web, api and console). So I think routes is the term to use and forgive me for the double-quotes.
I have made a simple diagram to show the structure I mean. What I need to know is is there a way to create a second api route that would be used exclusively by the frontend and would include only a limited set of priviledges. I imagine something like /frontapi/ or /webapi/ as opposed to /api/ which is used now by the backend.
Thanks a lot for your help and please correct me if I am using wrong terminology.
EDIT
Thank you all for answering the part regarding separating the route prefix and the api route files.
One part of the question that I realized late that I hadn't made clear was the importance of separating the API Keys for both APIs since I think that is the main security issue and what would really make then two individual API "Channels or ways". I think that is one reason why I was confusing about the terminology because "way" sounded to me more separate that just a "route". I've also edited the question to reflect that. Thank you again for taking the time to help.
You can decompose routes in as many files as you want, you can also give each file its own prefix (like how api.php routes start with /api)
The modification need to be done in App\Providers\RouteServiceProvider
//in map() add $this->mapApiTwoRoutes()
public function map()
{
$this->mapApiRoutes();
$this->mapApiTwoRoutes();//<---this one
$this->mapWebRoutes();
}
//now add the method mapApiTwoRoutes
protected function mapApiTwoRoutes()
{
Route::prefix('api2')//<-- prefix in the url
->middleware('api')//<-- api middleware (throttle and such check App\Http\Kernal.php)
->namespace('App\Http\Controllers') //<-- you can modify the namespace of the controllers
->group(base_path('routes/apiTwo.php'));//<-- file containing the routes
}
And that's it.
You need to define a new route file, firstly add a new entry $this->mapApi2Routes(); in the map() function in app\Providers\RouteServiceProvider.
Then add a new function in that file, basically copying the mapApiRoutes() function, call it mapApi2Routes(). You can use different middleware etc. for the new file.
The last step would be adding a new file api2.php in the routes folder.

Laravel 5.3 API Versioning

I am trying to get api versioning in place for an API I am working on, I found this post that explained how to do it using middleware and replacing a string in the route itself. Basically specifying routes like this.
Route::group(['middleware' => ['api-version']], function() {
Route::get('/endoint', ['uses' => '{api-namespace}\EndpointController#endpoint']);
});
However, when I attempt this I get the following error
Class App\Http\Controllers\{api-namespace}\EndpointController does not exist
It would appear that the container is verifying the existence of route controller files prior to running the middleware which does the replacing. I have added the middleware to the $routeMiddleware in the Http Kernel file.
How can I accomplish this before it checks for the existence of the file?
I thought about adding this to the applications global middleware but I do not want this to run on web only on api calls
Create a different file for next version of API has some downside.
You have to create all the routes from version 1
and in my case version 2 was just some changes to 3 requests. that was the time I felt we need a fallback for this kind of operation.
then I created a simple Laravel package to support Laravel API versioning it adds fallback functionality to routes. I personally needed this long ago but didn't realize it will be achieved with such a tiny package.
https://github.com/mbpcoder/laravel-api-versioning
The problem is that uses actually tries to retrieve a class and then call the method inside, you shouldn't be encouraged to put any parameters there so restrain from doing so, instead try grouping your api routes under certain prefix and middleware like so:
Route::prefix('XXXXXXX')->group(['middleware' => ['api-version']], function() {
Route::get('/endoint', 'EndpointController#endpoint');
});
Note: My above assumption is made out of that you didn't handle changing {api-namespace} inside of your middleware class properly.
Stepping through the code allowed me to see that this is already handled by Laravel and all i needed to do was create a routes/api/v2.php file with the routes for version 2. The only problem I see is having to duplicate all routes which did not change from version 1 to version 2. I may look into modifying my RouteServiceProvider to actually inherit previous versions if they are not overridden in the requested api version rather than duplicating the routes code for every api version.

How to stop grails erasing custom validation errors

In my Grails app, I am using methods in a service to do complicated validation for user submitted data. Unfortunately, Grails is quietly sabotaging me.
I populate the domain instance with the user submitted data
I hand the instance off to the service, which analyzes the properties.
If errors are found I add them using
instance.errors.rejectValue('myValue','errors.customErrorCode','Error')
BEHIND THE SCENES, when the service passes the domain instance back to the controller grails checks for changed properties and calls validate() before returning the instance. (verifiable by seeing the beforeValidate event called on returning a domain instance from a service to a controller where one or more properties has changed)
That behavior clears any custom errors I have added and the instance I get back in the controller is now incorrectly without error.
How can I
A) stop grails from validating between service and controller
OR
B) prevent a validate() call from wiping my custom errors.
EDIT
So far I've found one partial answer,
If you use instance.get(params.id), grails will self validate behind the scenes wiping custom errors.
If you use instance.read(params.id) you can bypass this behavior to an extent.docs
But this solution is limited by domain relationships. Any other solutions welcome.
Seems that it is not custom validation. It can be because of transactional service. Service opens separate transaction for each method and clears entities after method end. You can find this mentioned in docs(read the last paragraph of part ). So errors dessappear not because of validation.
Don't know if your service is transactional. But if it is - you can add #NotTransactional annotation to method were you want not to loose errors. And
errors will be saved.
Hope it helped,
Matvei.
Not sure how your code looks like or what is causing the problem, but in any case I strongly suggest implementing custom validators in the domain class or in a command object within the constrains.
Here are some examples from grails docs:
http://docs.grails.org/2.4.0/ref/Constraints/validator.html

How to change scope/permissions with Microsoft.Web.WebPages.OAuth

Is there a way to change the scope/permission when using Microsoft.Web.WebPages.OAuth? The most logical place is when registering the client with OAuthWebSecurity.RegisterClient. I thought that the adding scope to the extraData parameter would possibly work, but I didn't have success with that.
Microsoft.Web.WebPages.OAuth does not expose the scope when authorizing with a client. I ended up adding custom DotNetOpenAuth clients to include my necessary scope.
The extradata is something you can pass about the provider and use it in tehe UI layer. For eg. extra data could be the icon to display when listing the provider to use for login.
Following post shows how you can write your own provider and plug it into your site
http://blogs.msdn.com/b/webdev/archive/2012/08/23/plugging-custom-oauth-openid-providers.aspx

Resources