Jwt Token decode - Symfony 4 - php

I am trying to solve a problem related with token request. It is my newArticle function (to add new article) in the controller:
public function newArticle(Request $request, EntityManagerInterface $entityManager): View
{
$data = json_decode($request->getContent(), true);
$title = $data['title'];
$content = $data['content'];
//$published_at = $data['published_at'];
$authorizationHeader = $request->headers->get('Authorization');
list(,$token) = explode(' ', $authorizationHeader);
$jwtToken = $this->JWTEncoder->decode($token);
$user_id = $data[$jwtToken];
$userId = $this->userRepository->findOneBy(['id' => $user_id['id']]);
$article = new Article();
$article->setTitle($title);
$article->setContent($content);
$article->setPublishedAt(new \DateTime());
$article->setUser($userId);
// Todo: 400 response - Invalid input
// Todo: 404 response - Response not found
// Incase our Post was a success we need to return a 201 HTTP CREATED response with the created object
if(in_array('ROLE_USER', $article->getUser()->getRoles(), true)) {
$entityManager->persist($article);
$entityManager->flush();
return View::create("You added an article successfully!", Response::HTTP_OK);
} else {
return View::create(["You are not a user! So please register to add an article!"], Response::HTTP_BAD_REQUEST);
}
}
It is working before adding token header authorization and now I got this error:
"error": {
"code": 500,
"message": "Internal Server Error",
"message": "Notice: Undefined offset: 1",
Can someone give me any suggestions?

I thing your problem is this line:
$user_id = $data[$jwtToken];
You should refactor that, think it should be something like:
$user_id = $data['user_id'];
or
$user_id = $jwtToken['user_id'];
Depending on what data contain each object/array is where you should look foor. In first place the error is for calling an offset on an array, so fixing that should be fine (or have a clearer error message from the log)

Related

Youtube Data API UnknowPart Error When Create Broadcasting

I'm trying to create Youtube live stream through my webpage via Youtube Data API. Whatever I tried, keep getting that error:
{
"error": {
"code": 400,
"message": "'{0}'",
"errors": [
{
"message": "'{0}'",
"domain": "youtube.part",
"reason": "unknownPart",
"location": "part",
"locationType": "parameter"
}
]
}
}
Unfortunately, this error doesn't explain anything, and I couldn't find anything to help me to solve it. I hope someone can explain what is going on here.
I put all relative files down below and added some comments.
web.php
Route::get('youtube/{task}', [YoutubeController::class, 'authenticate'])->name('youtube.authenticate');
Route::get('youtube/{task}/redirect', [YoutubeController::class, 'create'])->name('youtube.create');
YoutubeController.php
class YoutubeController extends Controller
{
private $youtube;
public function __construct(Request $request)
{
// like YoutubeStreamService or YoutubeUploadService
$this->youtube = new ("\App\Services\Youtube\Youtube" . ucfirst($request->route()->parameter('task')) . "Service");
}
public function authenticate($task)
{
return redirect()->away($this->youtube->authenticate($task));
}
public function create(Request $request, $task)
{
$this->youtube->create($request, $task);
}
}
I use an abstract class for authentication codes.
abstract class YoutubeAbstraction
{
// Called from the controller.
// Returns the url to google to authenticate the request.
public function authenticate($task)
{
return $this->client($task)->createAuthUrl();
}
// This code came from mostly Youtueb API documentation.
protected function client($task)
{
$scopes = [
'upload' => ['https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube.force-ssl'],
'stream' => ['https://www.googleapis.com/auth/youtube.force-ssl']
][$task];
$client = new Google_Client();
$client->setApplicationName("MyApp");
$client->setScopes($scopes);
$client->setAuthConfig(base_path("client_secret_{$task}.json"));
$client->setAccessType('offline');
return $client;
}
abstract public function create($request, $task);
}
YoutubeStreamService.php
class YoutubeStreamService extends YoutubeAbstraction
{
// This code came from Youtube API documentation completely.
// It contains only the required fields and their hard-coded values.
public function create($request, $task)
{
$client = $this->client($task);
$client->setAccessToken($client->fetchAccessTokenWithAuthCode($request->code));
$service = new Google_Service_YouTube($client);
$liveBroadcast = new Google_Service_YouTube_LiveBroadcast();
$liveBroadcastSnippet = new Google_Service_YouTube_LiveBroadcastSnippet();
$liveBroadcastSnippet->setTitle('my title');
$liveBroadcastSnippet->setScheduledStartTime('2021-04-04T20:00:00.00+03:00');
$liveBroadcast->setSnippet($liveBroadcastSnippet);
$liveBroadcastStatus = new Google_Service_YouTube_LiveBroadcastStatus();
$liveBroadcastStatus->setPrivacyStatus('private');
$liveBroadcast->setStatus($liveBroadcastStatus);
// If I add dd($liveBroadcast) here, I see the object.
// So the error is thrown by the function down below.
$response = $service->liveBroadcasts->insert('', $liveBroadcast);
print_r($response);
}
}
As per the official specification, your call to the LiveBroadcasts.insert API endpoint has to include the request parameter:
part (string)
The part parameter serves two purposes in this operation. It identifies the properties that the write operation will set as well as the properties that the API response will include.
The part properties that you can include in the parameter value are id, snippet, contentDetails, and status.
In PHP, that requirement boils down to having your API call like the one below:
$response = $service->liveBroadcasts->insert(
'id,snippet,status', $liveBroadcast);

Notice: Undefined offset: 0 in C:\wamp64\www\lynda2\src\Chatter\Middleware\Authentication.php on line 12

Hi i'm created a web service with Slim from a course of lynda "Building APIs in PHP Using the Slim Micro Framework" but when i want login, this error Occurs
Notice: Undefined offset: 0 in C:\wamp64\www\lynda2\src\Chatter\Middleware\Authentication.php on line 12
Authentication
namespace Chatter\Middleware;
use Chatter\Models\User;
class Authentication
{
public function __invoke($request, $response, $next)
{
$auth = $request->getHeader('Authorization');
$_apikey = $auth[0];
$apikey = substr($_apikey, strpos($_apikey, ' ') + 1);
$user = new User();
if (!$user->authenticate($apikey)) {
$response->withStatus(401);
return $response;
}
$response = $next($request, $response);
return $response;
}
}
User.php
<pre><code>
namespace Chatter\Models;
class User extends \Illuminate\Database\Eloquent\Model
{
public function authenticate($apikey)
{
$user = User::where('apikey', '=', $apikey)->take(1)->get();
$this->details = $user[0];
return ($user[0]->exists) ? true : false;
}
}
</code></pre>
index.php
<pre><code>
require 'vendor/autoload.php';
include 'bootstrap.php';
use Chatter\Models\Message;
use Chatter\Middleware\Logging as ChatterLogging;
use Chatter\Middleware\Authentication as ChatterAuth;
$app = new \Slim\App();
$app->add(new ChatterAuth());
$app->add(new ChatterLogging());
$app->get('/messages', function ($request, $response, $args) {
$_message = new Message();
$messages = $_message->all();
$payload = [];
foreach($messages as $_msg) {
$payload[$_msg->id] = ['body' => $_msg->body, 'user_id' => $_msg->user_id, 'created_at' => $_msg->created_at];
}
return $response->withStatus(200)->withJson($payload);
});
$app->get('/', function ($request, $response, $args) {
return "This is a catch all route for the root that doesn't do anything useful.";
});
// Run app
$app->run();
</code></pre>
The error is stating that when you "login" there is no Authorization header present.
$request->getHeader('Authorization') returns an empty array, so when you attempting to access the first element of the array, you get your error:
$_apikey = $auth[0]; // Will trigger error, since there are no elements in the array
Thus to aviod this error, get $apikey like this:
public function __invoke($request, $response, $next)
{
$auth = $request->getHeader('Authorization');
$_apikey = array_shift($auth);
if ($_apikey) {
$apikey = substr($_apikey, strpos($_apikey, ' ') + 1);
$user = new User();
if (!$user->authenticate($apikey)) {
return $response->withStatus(401);
} else {
return $next($request, $response);
}
} else {
// Authorization header is missing, therefore unauthorized access
return $response->withStatus(401);
}
}
This is an older thread, but in case anyone else is following this tutorial ... the code the OP posted was supposed to do exactly what it does - to fail if there is no authorization header present.
Looks like the OP missed one step: adding the bearer token to the request. In Postman, go to Authorization > Type > Bearer Token and paste a valid token in the input field. I believe that it was clearly stated in the tutorial. Afterward, everything works as expected.

Laravel Token Signature could not be verified

I'm using Laravel/Lumen as an API for the backend of a webapp and run into a hiccup.
In an example I have a route that does not need the user to be authenticated. But I do want to check in the routes controller if the user visiting has a valid token.
So I wrote the following:
if ($tokenFetch = JWTAuth::parseToken()->authenticate()) {
$token = str_replace("Bearer ", "", $request->header('Authorization'));
} else {
$token = '';
}
I believe the above will check the Bearer token is valid else it will return a blank variable.
The following is my entire Controller.
public function show($url, Request $request)
{
if ($tokenFetch = JWTAuth::parseToken()->authenticate()) {
$token = str_replace("Bearer ", "", $request->header('Authorization'));
} else {
$token = 'book';
}
return response()->json(['token' => $token]);
}
The Problem
If I a pass in a valid Token Bearer, it returns the token but if I pass in an invalid one I get the following error:
TokenInvalidException in NamshiAdapter.php line 62:
Token Signature could not be verified.
If I don't pass a token at all:
JWTException in JWTAuth.php line 195:
The token could not be parsed from the request
Is there a way to check if a token is passed and if it has then check if its valid, but also if one has not been passed then return a blank return?
You can wrap it inside try/catch block
public function show($url, Request $request)
{
try {
$tokenFetch = JWTAuth::parseToken()->authenticate())
$token = str_replace("Bearer ", "", $request->header('Authorization'));
}catch(\Tymon\JWTAuth\Exceptions\JWTException $e){//general JWT exception
$token = 'book';
}
return response()->json(['token' => $token]);
}
There are few exceptions that you might want to handle separately (jwt-auth/Exceptions)
Also as you're using laravel 5 you can global handling for JWT exceptions ,not recommended in this case but you should know of this option and choose yourself. app/Exceptions/Handler.php and inside render method add [at the top]
if ($e instanceof \Tymon\JWTAuth\Exceptions\JWTException) {
//what happen when JWT exception occurs
}
Yes it's possible to achieve what you want.
Check if a token is passed:
If you check in the documentation of parseToken you'll see that the algorithm to check if we pass a token is:
if (! $token = $this->parseAuthHeader($header, $method)) {
if (! $token = $this->request->query($query, false)) {
}
}
// which it will be in your case:
$hasToken = true;
$header = $request->headers->get('authorization');
if (! starts_with(strtolower('authorization'), 'bearer')) {
if (! $request->query('token', false)) {
$hasToken = false;
}
}
Check if a token is valid:
Please note that the NamshiAdapter use the Namshi\JOSE package so read the documentation here.
In NamshiAdapter.php as you can see the line who rise your error are:
if (! $jws->verify($this->secret, $this->algo)) {
throw new TokenInvalidException('Token Signature could not be verified.');
}
// in your case:
// + try to var_dump $this->secret, $this->algo
// + use Namshi\JOSE\JWS
// if you var_dump
$jsw = new JWS(['typ' => 'JWT', 'alg' => $algo]);
$jws = $this->jws->load($token, false);
// if you want to follow the documentation of Namshi\JOSE
$jws = JWS::load($tokenString, false, $encoder, 'SecLib');
// again var_dump for $this->secret, $this->algo
$isValidToken = ($jws->verify($this->secret, $this->algo));

Sorry, that page does not exist [code] => 34

POST /statuses/retweet is giving me this error while POST statuses/tweet and GET search/tweets are working fine.
public $host = "https://api.twitter.com/1.1/";
$con = $this->oauth();
$retweets = $con->post('statuses/retweet/', array('id' => $searchid));
The query will get the Status id_str of the object. It is in string format.
/**
* POST wrapper for oAuthRequest.
*/
function post($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'POST', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
API console gives me no error:
https://api.twitter.com/1.1/statuses/retweet/{id}.json
If you want to retweet the tweet with ID 1234 you need to send a POST request to
https://api.twitter.com/1.1/statuses/retweet/1234.json
It looks like you are trying to perform a GET request to
https://api.twitter.com/1.1/statuses/retweet/?id=1234
figured it out. Retweet ID cant be sent as paramemeter. It has to be added as part of url.
This is what i did. parameter to be null
$retweets = $con->post('statuses/retweet/'.$searchid, null);

Guzzle post gives me error 500, get works fine

I'm trying to build an API with api key and secret using laravel and guzzle. I am building both the api and the client using laravel.
I have a problem when I try to access a simple controller to get a json with a list of users from the database. It works fine when I'm not using the authentication, it fails when I do beacause I need to change to using post method so that the api gets the secret and the app_id:
GuzzleHttp \ Exception \ ServerException (500)
Server error response [url] http://myapi.api/api/v1/users [status code] 500 [reason phrase] Internal Server Error
On my client:
$_app_id = 'APP001';
$_app_key = '28e336ac6c9423d946ba02d19c6a2632';
$_api_url = 'http://myapi.api/api/v1/users';
$enc_request = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $_app_key, json_encode($request_params), MCRYPT_MODE_ECB));
$params = array();
$params['enc_request'] = $enc_request;
$params['app_id'] = $_app_id;
$client = new GuzzleHttp\Client();
$result = $client->post($_api_url, array(
'body' => $params
));
$res=$result->json();
var_dump($res);
On my API:
Route::group(array('prefix' => 'api/v1'), function(){
Route::resource('users', 'UsersController');
});
Route::filter('my.filter', function()
{
$applications = array(
'APP001' => '28e336ac6c9423d946ba02d19c6a2632', //randomly generated app key
);
try {
$enc_request = $_REQUEST['enc_request'];
$app_id = $_REQUEST['app_id'];
if( !isset($applications[$app_id]) ) {
throw new Exception('Application does not exist!');
}
$params = json_decode(trim(mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $applications[$app_id], base64_decode($enc_request), MCRYPT_MODE_ECB )));
if( $params == false ){
throw new Exception('Request is not valid');
$result['success'] = false;
}else{
$result['success'] = true;
}
} catch( Exception $e ) {
$result = array();
$result['success'] = false;
$result['errormsg'] = $e->getMessage();
}
if($result['success']==false){
return Response::make('Unauthorized', 401);
//I have tested and the APP never gets inside here, authentication is correct
}
});
My controller:
class UsersController extends BaseController {
public function index()
{
$users = User::orderBy('username', 'asc');
return Response::json(array(
'error' => false,
'users' => $users->get()->toArray()),
200
);
}
}
If I remove the filter and simply change post to get on my client, I can see the json that comes from my users controller. As soon as I change it back to post, I get my error again.
Route resource uses the store method to post to the same uri as the index method. As stated within here and scrolling down to the 'Actions Handled By Resource Controller' part.
I ended up changeing body to query and it worked fine as it was and could use the resource classes and guzzle at the same time.

Categories