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

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.

Related

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.

PROBLEM with HEADER for test API Jetstream Sanctum Laravel 8x with PERMISSION

i generated two tokens:
tokenA = As2 ... xxxxx //can perform ONLY create
tokenB = Bs2 ... xxxxx //can perform ONLY update
i have the following problem
$response = $this->withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$tokenA],
])->post('/api/store',$data);
$response->assertStatus(201);
//the store is made without problems
$response = $this->withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer '.tokenB,
])->put('/api/update',$dataUpdate);
$respone->assertStatus(200);
//the test fails and returns 403. As if you don't have permission to do that
while if I call only
$response = $this->withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer '.tokenB,
])->put('/api/update',$dataUpdate);
$response->assertStatus(200);
the update is performed without problems.
How can I run the store and then the update in sequence?
it appears that $response continues to hold the value of tokenA

Laravel test fails, but works on postman

I have a test for a user logging out and having their token deleted.
use RefreshDatabase;
public function setUp() :void {
parent::setUp();
\Artisan::call('migrate',['-vvv' => true]);
\Artisan::call('passport:install',['-vvv' => true]);
\Artisan::call('db:seed',['-vvv' => true]);
}
...
/**
* #test
*/
public function a_user_has_tokens_removed_when_logged_out()
{
// login
$this->withoutExceptionHandling();
$user = factory('App\User')->create();
$response = $this->post('/api/login', [
'username' => $user->email,
'password' => 'password'
]);
$token = json_decode($response->getContent())->access_token;
$this->assertTrue(!$user->tokens->isEmpty());
// logout
Passport::actingAs($user, ['*']);
$logout = $this->json('POST', 'api/logout')->withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token
]);
$this->assertTrue($user->tokens->isEmpty());
}
First I'm creating a user and logging them in so a token is created and related to their user account.
I'm asserting that the token exists after hitting the login route, which passes.
Then I'm calling the logout route which will delete all the tokens the user has:
public function logout() {
auth()->user()->tokens()->each(function($token, $key) {
$token->delete();
});
return response()->json('Logged out successfully', 200);
}
routes/api.php
Route::middleware('auth:api')->post('logout', 'AuthController#logout');
This assertion on the test above is failing:
$this->assertTrue($user->tokens->isEmpty());
If I do a dd($user->tokens); before the assertion to check what's going on, the token shows up - it still exists.
But If I hit this api/logout route with Postman, which has everything stored in MySQL, all the tokens are being deleted successfully.
I don't understand what's going on and why this test is failing. Or rather, I don't understand why the $token->delete() doesn't work on the test, but does via Postman. What's different?
Before executing the assert, reload the user model relations via $user->fresh(), to ensure the deleted relations are reflected in the instance.
I don't know why, but within the testing context, this is not done automatically.

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.

Best way to store laravel API tokens?

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');

Resources