Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Laravel api route and Invalid CSRF Token #115

Closed
OctavioSI opened this issue Feb 22, 2018 · 3 comments
Closed

Laravel api route and Invalid CSRF Token #115

OctavioSI opened this issue Feb 22, 2018 · 3 comments

Comments

@OctavioSI
Copy link

I am facing the same problem described in issue #85 , using Laravel 5.4 and passing an endpoint in my API (routes/api.php) as redirect_uri to dropbox.

After digging some possible causes to this problem, I have identified that line 178 of /Dropbox/Authentication/DropboxAuthHelper.php is likely to be the issue:
$tokenInStore = $this->getPersistentDataStore()->get('state');

As it seems, $tokenInStore relies in a variable stored in session, as @kunalvarma05 mentioned above the need to include session_start() on top of the script. However, Laravel's api routes do not use sessions (it also seems to be bad practice to do so) and I've tried to create a custom middleware in my api route so as to enable the use of sessions, such as:

Route::group(['middleware'=>'sessions'], function () { //precisa de session Route::get('dropbox/generatetoken', 'DropboxController@generateAccessToken'); });

Additionally, I had to create a middleware in Http/Middleware/Kernel.php:

protected $middlewareGroups = [ 'web' => [ ... ], 'api' => [ ... ], 'sessions' => [ \Illuminate\Session\Middleware\StartSession::class, ] ];

I was able to access the general $_SESSION variable this way, but the error remains. Logging $tokenInStore also shows that the variable is empty.

I was able, however, to get the access token string after commenting the following lines in the validateCSRFToken function of DropboxAuthHelper.php as even mentioned in issue #105
//Unable to fetch CSRF Token if (!$tokenInStore || !$csrfToken) { throw new DropboxClientException("Invalid CSRF Token. Unable to validate CSRF Token."); } //CSRF Token Mismatch if ($tokenInStore !== $csrfToken) { throw new DropboxClientException("Invalid CSRF Token. CSRF Token Mismatch."); }

Obviously, this approach appears to be incorrect as CSRF validation is not being made. I wonder if there are other Laravel users who could put together this authentication using api.php or if there is any other solution.

@joeyrush
Copy link

+1 I had this same issue with non API routes (where sessions were being utilised..)

Commenting out the CSRF checks solves the issue but when deploying and running composer install your changes will be wiped out. My temporary solution was to manually set the state using SessionPersistentDataStore class:

From your callback code:

$YourDropboxInstance->getAuthHelper()->getPersistentDataStore()->set('state', filter_var($_GET['state'], FILTER_SANITIZE_STRING));

@ryross
Copy link

ryross commented May 30, 2020

I ended up creating a SessionPersistantDataStore class

namespace App\Dropbox;

use Kunnu\Dropbox\Store\PersistentDataStoreInterface;

class SessionPersistentDataStore implements PersistentDataStoreInterface
{

    /**
     * Session Variable Prefix
     *
     * @var string
     */
    protected $prefix;

    /**
     * Create a new SessionPersistentDataStore instance
     *
     * @param string $prefix Session Variable Prefix
     */
    public function __construct($prefix = "DBAPI_")
    {
        $this->prefix = $prefix;
    }

    /**
     * Get a value from the store
     *
     * @param  string $key Data Key
     *
     * @return string|null
     */
    public function get($key)
    {
        return session($this->prefix . $key);
    }

    /**
     * Set a value in the store
     * @param string $key   Data Key
     * @param string $value Data Value
     *
     * @return void
     */
    public function set($key, $value)
    {

        return session([$this->prefix . $key => $value]);
    }

    /**
     * Clear the key from the store
     *
     * @param $key Data Key
     *
     * @return void
     */
    public function clear($key)
    {
        session()->forget($this->prefix . $key);
    }
}

and then I use it by setting the config:

$app = new DropboxApp(env('DROPBOX_APP_KEY'), env('DROPBOX_APP_SECRET'));
$dropbox = new Dropbox($app, ['persistent_data_store' => new SessionPersistentDataStore()]);

@kunalvarma05
Copy link
Owner

You can use your own persistent data store as documented in the Advanced Configuration section. Also, see @ryross's sample implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants