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’));
Related
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);
}
I need to be create a global varible to use in another route, i'm unfamiliar with the SLIM framework and everything I've searched isn't working.
So basically I grab the price in the route that shows the home screen, then i need to use that price in another route with creates a STRIPE API session. See below;
$app = new Slim\App;
$app->get('/pay/{price}', function (Request $request, Response $response, $args) {
$response->getBody()->write(file_get_contents("../../client/index.html"));
$key = "8881727727272";
$decrypted = openssl_decrypt(hex2bin($args['price']),'AES-128-CBC',$key); <---- CREATED HERE!!!
return $response;
});
$app->get('/success', function (Request $request, Response $response, $args) {
$response->getBody()->write(file_get_contents("../../client/success.html"));
return $response;
});
$app->get('/cancel', function (Request $request, Response $response, $args) {
$response->getBody()->write(file_get_contents("../../client/cancel.html"));
return $response;
});
$app->post('/create-session', function(Request $request, Response $response) use ($app) {
try {
$cafe = 'test';
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'name' => $cafe,
'description' => 'ordering',
'images' => [''],
'amount' => $decrypted, <--- Needs to be used again here!
'currency' => 'aud',
'quantity' => 1,
]],
'success_url' => 'http://localhost/success?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'http://localhost/cancel',
]);
createSession($session->id);
} catch (Exception $e) {
return $response->withJson($e->getJsonBody(), 400);
}
return $response->withJson($session);
});
If anyone has any ideas that would be great!! Thank you
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
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);
});
I am new to API with Laravel. I am trying to validate parameters sent into POST request through the Laravel's validate method.
Following data is the only parameter I am sending through the POST request. I want to validate device_id for uniqueness using Laravel's validate method.
data => {"device_id":"xxxxxx2C-9EA3-4FFB-B26D-E8E483xxxxxx","password":"ANVp285x","user_type":"1"}
I can validate the only data parameter however there is no proper response or error message it's throwing exception. My main motive is to validate device_id, password and user_type.
Here's my controller's store
public function store(Request $request) {
try {
$result = $this->validate($request, [
'data' => 'required',
// 'data.device_id' => 'required|unique:users|max:60',
// 'data.password' => 'required|min:6|confirmed',
// 'data.user_type' => 'required',
]);
$user = new User;
// Parameters from request
$data = json_decode($request->data, TRUE);
$user->device_id = $data['device_id'];
$user->password = bcrypt($data['password']);
$user->u_type = $data['user_type'];
// Parameters to be generated
$user->qr_code_image = "test_qr_code.png";
$user->access_code = MyHelper::generate_access_code();
$user->save();
$user = User::find($user->id);
$result = Fractal::item($user, new UserTransformer)->getArray();
if (!empty($result['data'])) {
$result['status'] = TRUE;
$result['message'] = 'Success';
} else {
$result['status'] = FALSE;
$result['message'] = 'Failed';
}
} catch (\Exception $e) {
$result['status'] = FALSE;
$result['message'] = 'Failed';
}
return $result;
}
You can use Illuminate\Support\Facades\Validator to validate requests in your API:
$validator = Validator::make($request->all(), [
"device_id" => "required|unique:devices",
"user_type" => "required",
"password" => "required",
]);
if ($validator->fails()) {
return response(
$validator->errors(),
400
);
}
I found the solution I did this with below approch,
$data = $request->data;
$data = json_decode($data, TRUE);
$status = 200;
$validator = Validator::make(
array(
"goal_title" => $data['goal_name'],
"family_id" => $data['family_id'],
"goal_frequency" => $data['goal_frequency'],
), array(
"goal_title" => "required|regex:/(^[A-Za-z0-9 ]+$)+/|:family_goals",
"family_id" => "required",
"goal_frequency" => "required:goal_frequencies",
)
);