Laravel and Dropbox WebAuth: "Missing CSRF token in session" - php

I'm using Laravel 5.0 and trying to Authorize with Dropbox. I'm loosely following this example: http://dropbox.github.io/dropbox-sdk-php/api-docs/v1.1.x/class-Dropbox.WebAuth.html
When I go to /start. I get redirected to Dropbox and click "Allow", but when I get redirected back to /finish, I keep getting Missing CSRF token in session. Does anyone have any ideas? I have read that $_SESSION doesn't work in Laravel but I'm not sure how else to go about it.
Here is the code I am working with:
public function start()
{
$authorizeUrl = $this->getWebAuth()->start();
return redirect()->away($authorizeUrl);
}
public function finish()
{
$test = $this->getWebAuth()->finish($_GET);
dd($test);
}
private function getWebAuth()
{
$appKey = 'key';
$appSecret = 'secret';
$appName = 'name';
$appRedirect = 'http://example.com/finish';
$appInfo = new Dropbox\AppInfo($appKey, $appSecret);
$csrfTokenStore = new Dropbox\ArrayEntryStore($_SESSION, 'dropbox-auth-csrf-token');
$webAuth = new Dropbox\WebAuth($appInfo, $appName, $appRedirect, $csrfTokenStore);
return $webAuth;
}
Update 1:
Okay so I tried getting it working with Laravel Socialite and the Dropbox Socialite provider. I changed my code to what is below, but I get an error when I hit /start. Driver [dropbox] not supported. I got really confused on step 3 of the instructions, so maybe I did something wrong there.
composer.json
"require": {
"laravel/framework": "5.0.*",
"dropbox/dropbox-sdk": "1.1.*",
"laravel/socialite": "~2.0",
"socialiteproviders/dropbox": "~1.0"
},
Controller
use Socialite;
class ExampleController extends Controller {
public function start()
{
return Socialite::with('dropbox')->redirect();
}
public function finish()
{
$user = Socialite::with('dropbox')->user();
dd($user->token);
}
}
config/app.php
'providers' => [
//'Laravel\Socialite\SocialiteServiceProvider',
'SocialiteProviders\Manager\ServiceProvider',
],
'aliases' => [
'Socialite' => 'Laravel\Socialite\Facades\Socialite',
],
app/Providers/EventServiceProvider.php
protected $listen = [
'SocialiteProviders\Manager\SocialiteWasCalled' => [],
];
Update 2:
I figured it out, I added this and it worked.
app/Providers/EventServiceProvider.php
protected $listen = [
'SocialiteProviders\Manager\SocialiteWasCalled' => [
'SocialiteProviders\Dropbox\DropboxExtendSocialite#handle',
],
];

Why reinvent the wheel, if you have a wrapper that can do this for you:
https://github.com/GrahamCampbell/Laravel-Dropbox
The reason is that the POST routes are protected with CSRF. If you do not want to use a wrapper, you need to disable this security layer, but nobody would recommend that.
Even better is using Laravel Socialite. Only the fact is here that Dropbox is not natively supported in it, but this package will solve that.
Credits to ceejayoz for helping with this!

Note: Using a Dropbox package as in #Blaatpraat's answer is generally a better idea than this. If you're dead-set on using your own logic, though:
Laravel 5 POST routes (Dropbox is posting back to you at the end of the process) are protected by default by the CSRF protection middleware. Because Dropbox doesn't know your Laravel app's CSRF token (nor does it know to send one), the _token parameter is missing and fails the middleware.
You'll need to modify app/Http/Middleware/VerifyCsrfToken.php to exempt this route. Where it says:
return parent::handle($request, $next);
You'll want something like this to bypass the CSRF check on certain routes:
if(\Request::is('finish') { return $next($request); }
return parent::handle($request, $next);

Related

Can we interate socialite with backpack for laravel?

We have the need to login user ONLY via OpenId (exactly Microsoft Azure AD OpenId Connect).
We understand how to use Socialite but we would like to integrate with Backpack For Laravel, because app is 90% base cruds and because we already have a paid licence.
How to integrate socialite with backpack for laravel?
Also ... we should integrate it with laravel-permissions that it's very easy to integrate with backpack for laravel
If you need socialite, I recommend not using the Backpack authentication at all. Just disable everything related to authentication in your config/backpack/base.php file (the routes mainly), code your own controller logic with socialite and plug in your own auth middleware and guard within that same config file, so that Backpack uses your auth instead of the default one.
It will be easier to code and maintain your own logic, rather than mangling the default auth to work the way you want it.
This is actually a working solution
config\backpack\base.php
'guard' => null,
.env
AZURE_CLIENT_ID=0e8b592f-asaaaasd4eac-a368-d0d52dbc14e0
AZURE_CLIENT_SECRET=b2r5442
AZURE_REDIRECT_URI=/sso/callback
config\services.php
// See https://socialiteproviders.com/Microsoft-Azure/#installation-basic-usage
'azure' => [
'client_id' => env('AZURE_CLIENT_ID'),
'client_secret' => env('AZURE_CLIENT_SECRET'),
'redirect' => env('AZURE_REDIRECT_URI')
],
Packages installed:
"laravel/socialite": "^5.2",
"lcobucci/jwt": "^4.1",
"socialiteproviders/microsoft-azure": "^4.2",
routes\web.php
Route::get('/login', [\App\Http\Controllers\AuthController::class, 'login'])->name('login');
Route::get('/sso/callback', [\App\Http\Controllers\AuthController::class, 'ssoCallback']);
app/Http/Controllers/AuthController.php
use Laravel\Socialite\Facades\Socialite;
use Lcobucci\JWT\Configuration;
....
public function login()
{
return Socialite::driver('azure')->scopes(['openid'])->redirect();
}
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect("https://login.microsoftonline.com/common/oauth2/v2.0/logout");
}
public function ssoCallback()
{
try {
$user = Socialite::driver('azure')->user();
}
catch (\Laravel\Socialite\Two\InvalidStateException $e) {
return redirect(route('login'));
}
catch (\GuzzleHttp\Exception\ClientException $e) {
return redirect(route('login'));
}
// Read the claims from token JWT using Lcobucci\JWT package
$configuration = Configuration::forUnsecuredSigner();
$token = $configuration->parser()->parse( $user->accessTokenResponseBody["id_token"] );
$claims = $token->claims()
// This is an example, it depends by your jwt
$full_name = $user->name;
$email = $user->email;
$app_user = User::firstOrCreate([
'name' => $full_name,
'email' => $email,
]);
auth()->login($app_user);
}

Elastic search configurations not working in laravel v5.3

I have setup new laravel v5.3 project and install elastic search driver to implement elastic search via composer. But when I reload my page then I always receive This page isn’t working even the elastic search is running on my system below is my complete code that I code.
composer.json
"require": {
"php": ">=5.6.4",
"elasticsearch/elasticsearch": "^6.0",
"laravel/framework": "5.3.*"
},
web.php
Route::get('/',array('uses' => 'ElasticSearch#addPeopleList'));
Controller
<?php
namespace App\Http\Controllers;
class ElasticSearch extends Controller
{
// elastic
protected $elastic;
//elastic cliend
protected $client;
public function __construct(Client $client)
{
$this->client = ClientBuilder::create()->build();
$config = [
'host' =>'localhost',
'port' =>9200,
'index' =>'people',
];
$this->elastic = new ElasticClient($config);
}
public function addPeopleList(){
echo "<pre>";
print_r($this->$elastic);
exit;
}
}
But when I refresh the page then This page isn’t working i received this message and page not loaded one thing that I want to let you know that I made no changes in app.php file of configuration. Please eduacate to solve this issue.
if You want to instantiate an elastic client with some configuration, You should use method ClientBuilder::fromConfig(array $config).
In your case it should be
<?php
$client = ClientBuilder::fromConfig([
'hosts' => [ 'localhost:9200' ]
]);
As You can notice above hosts must be provided as array.
Also I'm not sure that Elasticsearch client that You use have ElasticClient class.
Also if You provided actual code from your controller than it contains an error. You should call class properties like that: print_r($this->client) (without $ near the property name).
Finaly your controller should looks like this:
<?php
namespace App\Http\Controllers;
use Elasticsearch\ClientBuilder;
class ElasticSearch extends Controller
{
/**
* #var \Elasticsearch\Client
*/
protected $client;
public function __construct()
{
$this->client = ClientBuilder::fromConfig([
'hosts' => [
'localhost:9200',
],
]);
}
public function addPeopleList(){
echo "<pre>";
print_r($this->client);
exit;
}
}
And to add a document to the index You need to call this command according to the official documentation
$params = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'my_id',
'body' => ['testField' => 'abc']
];
$response = $client->index($params);
print_r($response);
Official documentation can be found here https://github.com/elastic/elasticsearch-php
P.S. Sorry for my English. It is far from perfect.

How to change the Auth Guard in Laravel Auditing?

I have used the Laravel Auditing plugin (http://www.laravel-auditing.com/docs/3.1) to log the all models changes.Am using different auth system but the Laravel Auditing
getLoggedInUserId()
using laravel core one so need to change that. i have forked this plugin and edited the function directly its worked. But i like to find another ways if you have idea share with me ?
protected function getLoggedInUserId()
{
try {
if (Auth::check()) {
return Auth::user()->getAuthIdentifier();
}
} catch (\Exception $e) {
return;
}
}
Unfortunately, until version 4 of the package, you couldn't change the user resolver without modifying the actual code.
However, from version 4 onwards, you can do so in the configuration file (config/audit.php).
The user resolver can be set in two ways.
As a Closure:
return [
'user' = [
'resolver' => function () {
return Auth::check() ? Auth::user()->getAuthIdentifier() : null;
},
],
];
As a FQCN:
return [
'user' = [
'resolver' => App\User::class,
],
];
TIP: You have to implement the OwenIt\Auditing\Contracts\UserResolver interface in the App\User class for this to work.
See the full documentation here.

JWT authentication in Laravel without database

I have a question regarding Authentication in Laravel 5.x. I’ve been specifically looking at tymondesigns/jwt-auth and irazasyed/jwt-auth-guard packages to do the JSON web token authentication token handling in my Laravel application.
I am not using a local database whatsoever, nor do I want to. I have environment variables set up in .env for my API’s URL, USERNAME & PASSWORD. The Guzzle PHP HTTP client is doing the trick just fine, connecting and returning data between the API and my application as needed.
However, I need to set up Authentication within my Laravel instance. I run into problems here, and the auth is wanting a DB connection.
$token = JWTAuth::attempt($credentials)
Here's the exception:
PDOException in Connector.php line 55:
SQLSTATE[HY000] [14] unable to open database file
How can I make use of JWT without using a database?
How can I COMPLETELY shut-off database connections within Laravel?
Thanks.
UPDATE:
Using tymon/jwt-auth, I've set things up within the routes, Kernel, Middleware, etc.
I created a "claim" successfully, but I need to create the token by encoding the "payload."
$this->username = $request->username;
$sub = $this->username;
$iat = time();
$jti = md5($sub . $iat);
$aud = env('APP_URL');
$this->claims = [
'sub' => $sub,
'iat' => $iat,
'exp' => time() + (2 * 7 * 24 * 60 * 60),
'nbf' => $iat,
'iss' => 'khill',
'jti' => $jti,
'aud' => $aud,
];
$payload = JWTFactory::make($this->claims);
How do I get the custom token?
You should define a custom Authentication Provider and set it in config/jwt.php.
Example of provider
Put this class anywhere you like.
namespace MyNamespace;
use Tymon\JWTAuth\Providers\Auth\AuthInterface;
class MyCustomAuthenticationProvider implements AuthInterface
{
public function byCredentials(array $credentials = [])
{
return $credentials['username'] == env('USERNAME') && $credentials['password'] == env('PASSWORD');
}
public function byId($id)
{
// maybe throw an expection?
}
public function user()
{
// you will have to implement this maybe.
}
}
Example of configuration
In the providers array in config/jwt.php, change this:
'auth' => 'Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter',
to this:
'auth' => 'MyNamespace\MyCustomAuthenticationProvider',
Other considerations
Using the env() function anywhere is not good practice. It's better to use it in your config files, and then use the config() function anywhere else.
You may need to reimplement also the User Provider.
JWTAuth::attempt() won't help you with this, because it hits the database for you behind the scenes. You need some other way to check the environment credentials.
Add a custom method to a class somewhere which will do that for you or pass the credentials against the API you are hitting with Guzzle.
Code example:
public function authenticate($username, $password)
{
if(!$username === env('USERNAME') or !$password === env('PASSWORD')) {
// return a message that the user could not be authenticated or false.
}
// Generate the JWT token here and store it somewhere.
}
As a quick fix I decided to implement the following custom code...
1) Created custom middleware to handle the logic.
class CustomMiddleware
{
protected $loginPath = 'login';
public function handle($request, Closure $next) {
$logged_in = $request->session()->get('logged_in');
if (!$logged_in) {
return redirect()->guest('login')->with('flag','1');
}
return $next($request);
}
}
2) Added a reference to the middleware class.
class Kernel extends HttpKernel
{
protected $routeMiddleware = [
'custom' => \App\Http\Middleware\CustomMiddleware::class,
];
}
3) Added it to routes.php.
Route::group(['middleware' => ['custom']], function () {
// Add routes here
}
yes.
you can create jwt token without database using tymondesigns/jwt-auth package...
for that you have to use jwt::encode method...
let me explain ...
first you have to put your credential in .env file...
then i am recomending you to use custom claims ...
after that you can create jwt token using below code ...
$customClaims = ['foo' => 'bar', 'baz' => 'bob'];
$factory = JWTFactory::customClaims($customClaims);
$token = JWTAuth::encode($payload);
for further details you can refer below link
wiki

Laravel cURL POST Throwing TokenMismatchException

I have a problem with POST cURL request to my application.
Currently, I'm building RESTFUL registration function using laravel 5.
The routes for this is example is
localhost:8000/user/create
I pass value using cURL function on terminal
curl -d 'fname=randy&lname=tan&id_location=1&email=randy#randytan.me&password=randytan&remember_token=Y&created_at=2015-03-03' localhost:8000/auth/register/
And this is my routes.php
Route::post('user/create', 'UserController#create');
And this is my function to store the registration user
public function create()
{
//function to create user.
$userAccounts = new User;
$userAccounts->fname = Request::get('fname');
$userAccounts->lname = Request::get('lname');
$userAccounts->id_location = Request::get('id_location');
$userAccounts->email = Request::get('email');
$userAccounts->password = Hash::make(Request::get('password'));
$userAccounts->created_at = Request::get('created_at');
$userAccounts->save();
return Response::json(array(
'error' => false,
'user' => $userAccounts->fname . " " . $userAccounts->lname
), 200);
}
Executing the cURL syntax above, I'm getting this error TokenMismatchException
Do you have any ideas?
Because I'm implementing middleware only in my few urls, and this cURL registration url is not tight into any authentication mechanism.
Thanks before.
In Laravel 5 (latest version) you can specify routes you want to exclude in /app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
'rest-api/*', # all routes to rest-api will be excluded.
];
}
Hope this helps.
Laravel 5 enforces CSFR token authentication in middleware by default.
you can disable CSFR on selected route Here is the link
or you can try some of these solutions. Hope so it will help.
changing your csfr token method /app/Http/Middleware/VerifyCsrfToken.php
public function handle ($request, Closure $next)
{
if ( !$request->is("api/*"))
{
return parent::handle($request, $next);
}
return $next($request);
}
In my case, i needed to add the route on api.php instead of web.php

Categories