Best way to store laravel API tokens? - laravel

I'm currently setting up a new project in Laravel.
Upon logging in I want to store the logged in user's token. so, I can make other API request in other controllers using this format,
Code:
$response = $client->request('POST', '/api/user', [
'headers' => [
'Authorization' => 'Bearer '.$token,
'Accept' => 'application/json',
],]);
I'm not quite sure, how I will store $token so it can be accessed in all controllers.

Normally, APIs that use token based authentication require the token to be sent with each request as the APIs are, hopefully, stateless. This means that whatever controller of yours is handling the user request will also have the token to perform other requests in the background. In your controller, you should be able to retrieve the token like so:
class MyController
{
public function index(Request $request)
{
$authorization = $request->header('Authorization');
$token = null;
if (substr($authorization, 0, 7) === "Bearer ") {
$token = substr($authorization, 7);
}
// in theory, this is obsolete as your controller should only
// be called if there is a valid token present on the request
if ($token === null) {
abort(403); // or whatever
}
$client = ...; // initialize the client
$response = $client->request('POST', '/api/user', [
'headers' => [
'Authorization' => 'Bearer '.$token,
'Accept' => 'application/json',
],
]);
// return some response to the user
}
}
Obviously it makes sense to extract the token parsing into its own function which lives in a base controller that all other controllers inherit from. In your concrete example you could also simply use ['headers' => ['Authorization' => $request->header('Authorization')]] as you only want to forward the header.
Old answer which doesn't make any sense:
Store the token in the session data of the user:
session(['token' => $token]);
The array indicates that you set data in the session. Retrieving the token is even easier:
$token = session('token');

Related

How to do concurrent guzzle http post request to rest api in laravel?

I want to make concurrent Guzzle http requests in laravel to rest api i have users in 100k i want to perform billing for users.
Currently my guzzle http is doing synchronous calls to rest api which is taking 6 hours to complete 100k post requests and the requests does not have any call backs they are just post request with users msisdn and unique id in json format.
How to do concurrent 50 requests per second so that billing is performed quickly.
Following is part of my code which i use taken from https://docs.guzzlephp.org/en/stable/quickstart.html#concurrent-requests
$requests = function ($total) {
$url = "url here";
$auth = base64_encode($username . ":" . $password);
for ($i = 0; $i < $total; $i++) {
$msgdata =[
'msisdn'=>$msisdn,
$subscription
=>$subscriptionInfo];
yield new Request('post', $url,
[
'headers' =>
[
'Content-Type' => 'application/json',
'Authorization' => $authorizaton
],
'body' => json_encode($msgdata)
]);
}
$pool = new Pool($client, $requests(50), [
'concurrency' => 5,
'fulfilled' => function (Response $response, $index) {
// this is delivered each successful response
echo $response;
},
'rejected' => function (RequestException $reason, $index) {
// this is delivered each failed request
echo $reason;
},
]);
// Initiate the transfers and create a promise
$promise = $pool->promise();
// Force the pool of requests to complete.
$promise->wait();
i am getting response as
"status":401,"error":"Unauthorized"
But request params are not incorect idk why it is giving response as incorect
finally i found the solution to my problem, the problem was in request header and body parameters.
changed this
yield new Request('post', $url,
[
'headers' =>
[
'Content-Type' => 'application/json',
'Authorization' => $authorizaton
],
'body' => json_encode($msgdata)
]);
to
yield new Request('post', $url,
[
'Content-Type' => 'application/json',
'Authorization' => $authorizaton
],
json_encode($msgdata)
);

Laravel Current User off of a Fetch Request

so I am trying to get the active user off of a fetch request to my backend.
My front end code is:
let apiToken: string | null = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
fetch('http://192.168.0.6:8000/api/testURL', {
method: "POST",
//#ts-ignore
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text-plain, */*',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': apiToken
},
credentials: 'same-origin',
body: JSON.stringify(data)
})
.then(function(response): void {
console.log(response);
})
.catch(function(err): void {
console.log(err);
});
I have a CSRF token in a meta tag that is generated from csrf_token();
My backend code is:
Route::post('/testURL', function(Request $request)
{
$status = $request->input('status');
$comment = $request->input('comment');
$prospectType = $request->input('prospectType');
$leadId = $request->input('leadId');
$requestUser = $request->user();
return response()->json([
'status' => $status,
'comment' => $comment,
'prospectType' => $prospectType,
'leadId' => $leadId,
'user' => $requestUser
]);
});
The end result from the API call back shows 'user' as null.
I have tried Auth::user() & Auth::id() and they all return null.
I am at a lose and tried using Sanctum to create a validation token which when I added an auth:sanctum middleware it returned a 302 to redirect.
(The same redirect is happening when I apply a vanilla "auth" to a non-Sanctum token'd request).
The request out of all of this!
I want to ensure I have user by ID validation when I send up the request from the frontend to the backend.
I figured it out, the reason the request was not working correctly was the sanctum.php config file did not have my local IP (what I am running my php artisan serve off of) in its 'stateful' array.
I hope this helps anyone! That was five hours of my life.

Laravel 7: unit test set default request header in setUp()

I want to set my headers for all requests in a test in the setUp method instead of doing it to all the tests separately.
Is there an easy way to do this?
So par example:
$this->withHeaders([
'Authorization' => 'Bearer ' . $response['data']['token'],
'Accept' => 'application/json'
])
To:
setUp(){
$this->setHeaders([
'Authorization' => 'Bearer ' . $response['data']['token'],
'Accept' => 'application/json'
]);
}
Of course. You could create an intermediary parent class TestCaseWithToken (or whatever you'd like to name it) that is going to extend the PHPUnit\Framework\TestCase and add your overriden method there
protected function setUp(): void
{
parent::setUp();
// set your headers here
$this->withHeaders([
'Authorization' => 'Bearer ' . $this->getBearerToken(),
'Accept' => 'application/json'
])
}
protected function getBearerToken()
{
return '';
}
Additionally if your token changes in the $response variable, you could build a function that returns the token so you could easily override the method in the individual test classes. You could opt for a class property and a setter method, will work the same.
If you want to get the token of the user you want to log in, it can be easily done. Just make the getBearerToken method return something like auth('api')->login($this->authUser);(this is goint to return the actual token) and set the $authUser once per test file. Hope this helps you in the right direction.

Getting null when posting data using Guzzle Client in Laravel

Am working on an a Laravel application whereby am posting some data to an API using Guzzle Http Client. The APIhas passport authentication which requires the token of the authenticated user to be passed on the headers. The headers also accept application/json as content-type and accept type.
I am also passing the data via POST request
The problem is that I keep getting a null response.
public
function post_policies($data, $token, $url) {
$client = new Client();
$serverURL = 'http://localhost/digital-apps-apis/public'.
'/'.$url;
$body = $client - > request('POST', $serverURL, $data, [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer '.$token,
]) - > getBody();
$contents = $body - > getbody() - > getContents();
$data = json_decode($contents);
dd($data);
}
$body = $client->request('POST', $serverURL , $data, [
'debug' => true, //switch it to false before go live
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $token,
]]
)->getBody();
You must define your headers in the headers array.
Since it's a post i don't see you actually sending any data in the body. But if you do use the form_params array exactly like i used the headers array.

LARAVEL & VUE: How can I get the API_TOKEN of the logged in user with an API request?

I have a SPA using VUE and LARAVEL 5.8
I have setup an API_TOKEN associated to the logged in user. Everything works fine right after the login. I get the API_TOKEN, I save it into a var and I send it together with the Axios request. In Laravel I have a middleware that is taking care of the token and comparing it with the one setup on the logged in user.
the problem though occur when session expires. Because I still can navigate the private pages and make API requests to save and delete content. This is possible I think because I still have the same API_TOKEN saved in the var and the middleware apparently doesn't get that the session is expired.
So I want to obtain the API_TOKEN every time I'm doing an Ajax, request so when the session expires, I won't get the token and therefore, I won't be able to complete the request.
This is my setup.
web.php is where I have the only php route that points to a singlePageController:
Auth::routes();
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');
Then in the singlePageController I return the view:
class SinglePageController extends Controller
{
public function index() {
return view('app', ['loggedUser' => auth()->user()]);
}
}
Then I have the api.php where I have the API routes. As you can see at the end I have the middleware to make it private. Just to make an example this is the one I use for updating the content:
Route::put('event/update/{slug}', 'EventController#update')->middleware('auth:api');
Then the related controller of that API route:
public function update(Request $request, $slug)
{
$event = Event::where('slug', $slug)->first();
$event->title = $request->input('title');
return new EventResource($event);
}
And in the end this is the Resource I use to define what and how the API data is going to be displayed:
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'curator' => $this->curator,
'featured_image' => $this->featured_image,
'body' => $this->body,
'date' => $this->date
];
}
So this above is the flow I have. Then when I do an axios call to update the content, I'm doing something like:
axios({
method: 'PUT',
url: '/api/event/update/' + this.$route.params.slug + '?api_token=' + this.isLogged.apiToken,
data: dataToSave,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
.then((response) => {
this.getNotification('Success: The Event has been saved');
})
.catch((error) => {
this.getNotification('Error: Impossible saving the event');
console.log(error);
})
Do you know how to make it? or if there is a better way to accomplish that?
you and do like, your login method should like this.
public function login(Request $request)
{
if (Auth::attempt(['email' => $request['email'], 'password' => $request['password']])) {
$user = Auth::user();
$success = $user->createToken(config('app.name'))->accessToken;
return response()->json(["token" => $success, 'status' => 200]);
} else {
return response()->json(['message' => "Email or Password do not match"], 401);
}
}

Resources