Automatically generate/call new jwt token if token expires php slim 4 - php

I really appreciate it if someone can help me here. Is there a way I can call the endpoint that generates the api jwt token within my container, anytime the last one expires? below is auth part of my container
App::class => function (ContainerInterface $container) {
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->add(new Tuupola\Middleware\JwtAuthentication([
"secret" => $_ENV['JWT_SECRET'],
"ignore" => ["/api/token","/users"], //s
"error" => function ($response, $arguments) {
$data["status"] = "error";
$data["message"] = $arguments["message"];
//$app->post('/api/token', \App\Action\ApiAuthAction::class)->setName('user-api');
return $response
->withHeader("Content-Type", "application/json")
->getBody()->write((string)json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
]));
return $app;
},
This is my auth file
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $args = []): ResponseInterface
{
$userData = $this->userReader->findUserByEmail($request->getParsedBody());
if ($userData) {
$now = new DateTime();
$future = new DateTime($_ENV['JWT_EXPAIRED'] . " minutes");
$jti = (new Base62)->encode(random_bytes(16));
$payload = [
"iat" => $now->getTimeStamp(),
"exp" => $future->getTimeStamp(),
"jti" => $jti,
"sub" => $userData->email
];
$secret = $_ENV['JWT_SECRET'];
$token = JWT::encode($payload, $secret, "HS256");
$data["token"] = $token;
$data["expires"] = $future->getTimeStamp();
$response->getBody()->write((string)json_encode([
'success' => true,
'message' => $token
]));
} else {
$response->getBody()->write((string)json_encode([
'success' => false,
'message' => 'Invalid Email or Password'
]));
}
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}

Related

Laravel send data from controller to middleware

I'm trying to pass token_id and user_id from controller to middleware.
I have some hard time with that.
This is the code that I'm trying to run.
class UserController extends Controller
{
protected $user_id;
protected $token_id;
public function __construct()
{
$user_id = $this->user_id;
$token_id = $this->token_id;
$together = $user_id . ':' . $token_id;
$this->middleware('check.auth:' . $together);
}
public function setLogin(Request $request)
{
$credentials = request(['email', 'password']);
if (!Auth::attempt($credentials)){
Secure::checkFailedAuth($request->email, $request->password);
return response()->json(['response' => false, 'status' => 400, 'message' => 'Provided details are not correct!'], 400);
}
$user = Auth::user();
$tokenResult = $user->createToken($user->name);
$token = $tokenResult->token;
$token->save();
$this->user_id = Auth::id();
$this->token_id = $tokenResult->token->token_id;
return response()->json(['result' => true, 'status' => 200, 'message' => 'Login Successful', 'data' => Auth::user(), 'token' => $tokenResult->accessToken ], 200);
}
When I run that I have no errors, but there is null on both user_id and token_id.
Any ideas why?

Generate jwt with user information

I using HttpBasicAuthentication from Slim/PHP to protect access to my "/login" route, after validate access a JWT will be create to give access to all routes. So I wanna to generate a custom jwt with user profile information from DB but I cannot get user’s information… all arguments are empty.
How to solve that?
$app->add(new \Tuupola\Middleware\HttpBasicAuthentication([
"path" => "/login",
"realm" => "Protected",
"authenticator" => new LoginAuthenticator(),
"error" => function ($response, $arguments) {
$data = [];
$data["status"] = "error";
$data["message"] = $arguments["message"];
$body = $response->getBody();
$body->write(json_encode($data, JSON_UNESCAPED_SLASHES));
return $response->withBody($body);
},
"before" => function ($request, $arguments) {
return $request->withAttribute("user", $arguments["user"]);
}
]));
Route
$app->get('/login', function (Request $request, Response $response) use ($app) {
$params = (object) $request->getParams()
$key = $this->get("secretkey");
$token = array(
"user" => $params->user,
"email" => $params->email,
"age" => $params->age
);
$jwt = JWT::encode($token, $key);
return $response->withJson(["jwt" => $jwt], 200)
->withHeader('Content-type', 'application/json');
});
if you have $token , $key, algorithm , you can retrieve payload with code down
JWT::decode($token, $key, array(‘HS256’));

Why is the decoding of my JSON response not working in my Laravel Controller?

I have a AuthController where I register the user and also log in the user. When the user is registered, I automatically log the user in by calling the login method. The login method returns a JSON object that looks like this
"meta": {
"headers": {},
"original": {
"success": true,
"token": "token is here"
},
"exception": null
}
How do I extract token from that JSON object that I get from $this->login($request)? Because right now $token returns Null.
public function login(Request $request)
{
$input = $request->only('email', 'password');
$token = null;
if (!$token = JWTAuth::attempt($input)) {
return response()->json([
'success' => false,
'message' => 'Invalid Email or Password',
], 401);
}
return response()->json([
'success' => true,
'token' => $token,
]);
}
public function register(RegistrationFormRequest $request)
{
$user = new User();
$user->user_name = $request->user_name;
$user->first_name = $request->first_name;
$user->last_name = $request->last_name;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->role_id = 7;
$user->subscription_plan_id = 1;
$user->save();
$token = json_decode($this->login($request), TRUE)['token'];
return response()->json([
'success' => true,
'data' => $user,
'meta' => $token,
], 200);
}

How to send form fields with Guzzle 6?

I am developing my unit tests for an API created in Symfony4
Reading the Guzzle documentation I generated the following code:
File SecurityControllerTest.php
$client = new Client([
'base_uri' => 'http://localhost/sacrepad/sacrepad-api/public/index.php/',
'timeout' => 2.0,
]);
$data = array();
$data['email'] = 'admin#admin.com';
$data['password'] = '12345678';
$data2 = array();
$data2['json'] = $data;
$formData = json_encode($data);
$response = $client->request('POST', 'login', [
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'form_params' => [
'json' => $formData,
]
]);
$body = json_decode($response->getBody(), true);
File SecurityController.php
/**
* #Route("/login", name="login", methods={"POST"})
*/
public function login(Request $request,Helpers $helpers,ValidatorInterface $validator, JwtAuth $jwtauth) {
$data = array(
'status' => 'error',
'code' => 400,
'msg' => 'data not received'
);
$json = $request->request->get('json');
$params = json_decode($json);
}
When I run the tests with the phpunit command, I get the following error:
1) App\Tests\SecurityControllerTest::testAuth GuzzleHttp\Exception\ServerException: Server error: `POST http://localhost/sacrepad/sacrepad-api/public/index.php/login` resulted in a `500 Internal Server Error` response:
If I change the name of the request:
$json = $request->request->get('json2');
It works and it returns me the following:
array(3) {
["status"]=>
string(5) "error"
["code"]=>
int(400)
["msg"]=>
string(18) "data not received"
}
Any ideas on how to make it work and send the parameters?
i build a class for working with guzzle
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class Api
{
protected $client;
protected $url;
public function __construct()
{
$this->client = new Client([
'verify'=>false
]);
$this->url = 'http://localhost/sacrepad/sacrepad-api/public/';
}
public function get($endpoint, $params = [], $headers = [])
{
$response = $this->sendRequest(
'GET',
$this->url . $endpoint,
$params,
$headers
);
return $response;
}
public function post($endpoint, $params = [], $headers = [])
{
$response = $this->sendRequest(
'POST',
$this->url . $endpoint,
$params,
$headers
);
return $response;
}
public function sendRequest($type, $url, $params = [], $headers = [])
{
if ($type == 'GET') {
$data = [
'query' => $params
];
} elseif ($type == 'FILE') {
$type = 'POST';
$data = [
'multipart' => $params // TODO implements later
];
} else {
$data = [
'json' => $params
];
}
if (!empty($headers)) {
$data['headers'] = $headers;
}
$data['headers']['X-REAL-IP'] = $_SERVER['REMOTE_ADDR'];
$data['headers']['User-Agent'] = $_SERVER['HTTP_USER_AGENT'];;
$data['headers']['X-Platform'] = 'web';
try {
$response = $this->client->request(
$type,
$url,
$data
);
if (in_array($response->getStatusCode(), ['200', '403', '404'])) {
return json_decode($response->getBody());
}
return false;
} catch (RequestException $re) {
if (in_array($re->getResponse()->getStatusCode(), ['403', '404', '422'])) {
return json_decode($re->getResponse()->getBody());
}
return json_decode($re->getResponse()->getBody());
} catch (Exception $e) {
return false;
}
}
}
when i want to send a post request it would be like this
$response = (new Api())->post('index.php/',[
'email'=> 'admin#admin.com',
'password' => '123456'
]);
now it will send a post request to index.php and send email and password data i hope it would be helpful

JWT decode() must be of the type array error

Here I have some slim PHP code which is log in and a function to check whether it decode the JWT that store in the header.
$app->post('/login', function ($request, $response) {
$input = $request->getParsedBody();
$settings = $this->get('settings'); // get settings array.
$sql = "SELECT id, password FROM users WHERE id= :id";
$sth = $this->db->prepare($sql);
$sth->bindParam("id", $input['id']);
$sth->execute();
$user = $sth->fetchObject();
// verify user id
if(!$user) {
return $this->response->withJson(['error' => true, 'message' => 'NO ID '], 404)->withHeader('Content-type', 'application/json;charset=utf-8', 404);
}
// Compare the input password and the password from database for a validation
if (strcmp($input['password'],$user->password)) {
return $this->response->withJson(['error' => true, 'message' => 'These credentials do not match our records.'], 404)->withHeader('Content-type', 'application/json;charset=utf-8', 404);
}
$payload = array(
"iat" => time(),
"exp" => time() + 36000,
// "id" => $input['id']
"context" => [
"user" => [
"id" => $input['id']
]
]
);
try {
$token = JWT::encode($payload, $settings['jwt']['secret'],"HS256"); // $token store the token of the user
} catch (Exception $e) {
echo json_encode($e);
}
return $this->response->withJson($payload,200)
->withHeader('Content-type', 'application/json;charset=utf-8', 200)
->withAddedHeader('Authorization', $token);
});
$app->get('/get', function ($request, $response) {
$jwt = $request->getHeader("Authorization");
$settings = $this->get('settings');
$token = JWT::decode($jwt, $settings['jwt']['secret'], "HS256"); // $token store the token of the user
if ($token) {
return $this->response->withJson($token, 200)
->withHeader('Content-type', 'application/json;charset=utf-8', 200);
}
return $this->response->withJson($token,401)
->withHeader('Content-type', 'application/json;charset=utf-8', 401);
});
But it when i try to run http://localhost:8080/get it returns an error which is
Argument 3 passed to Firebase\JWT\JWT::decode() must be of the type array.
Why does it happen and how can i fix it?
Try to follow what the error says:
$token = JWT::decode($jwt, $settings['jwt']['secret'], ["HS256"]);
You can see the Example of using here
If i decode in the same function it returns the decoded JWT, but if i decode in other function it returns an error. How to pass the jwt to other function?
$app->post('/login', function ($request, $response) {
$key = "supersecretkeyyoushouldnotcommittogithub";
$input = $request->getParsedBody();
$settings = $this->get('settings'); // get settings array.
$sql = "SELECT id, password FROM users WHERE id= :id";
$sth = $this->db->prepare($sql);
$sth->bindParam("id", $input['id']);
$sth->execute();
$user = $sth->fetchObject();
// verify user id
if(!$user) {
return $this->response->withJson(['error' => true, 'message' => 'NO ID '], 404)->withHeader('Content-type', 'application/json;charset=utf-8', 404);
}
// Compare the input password and the password from database for a validation
if (strcmp($input['password'],$user->password)) {
return $this->response->withJson(['error' => true, 'message' => 'These credentials do not match our records.'], 404)->withHeader('Content-type', 'application/json;charset=utf-8', 404);
}
$payload = array(
"iat" => time(),
"exp" => time() + 36000,
// "id" => $input['id']
"context" => [
"user" => [
"id" => $input['id']
]
]
);
try {
$token = JWT::encode($payload, $key); // $token store the token of the user
} catch (Exception $e) {
echo json_encode($e);
}
// return $this->response->withJson($payload,200)
// ->withHeader('Content-type', 'application/json;charset=utf-8', 200)
// ->withHeader('Authorization', $token);
$decoded = JWT::decode($token, $key, array('HS256'));
print_r($decoded);
});

Categories