Jwt-auth: Can I use a laravel session with jwt-auth?

Created on 12 Aug 2015  路  2Comments  路  Source: tymondesigns/jwt-auth

I tried to use session('key', value') but it seems it does not work.
Not sure if it麓s supposed to work with jwt at all?
If not, what is the best way to save user-dependent temp data on the server side?

Most helpful comment

I would avoid using session() as it creates a php session which results in a cookie being sent to the client which the server will expect to receive the next time it wants to fetch something specific about the "session" for the user. So if you're writing an API, for example, and you aren't sending back the cookies you receive from the server, your session data won't be available.

As an alternative, you could use a cache service such as memcached or redis -- Laravel has support for both. The benefit of using either of these services is that they can work in a distributed manner if your application/service ever needs to grow beyond more than one server.

I've done something similar in the past so here's something that could get you started:

namespace YourApp\Services;

use YourApp\User;
use Tymon\JWTAuth\JWTAuth;
use Illuminate\Contracts\Cache\Repository;

class UserTempStorage
{

    const USER_CACHE_NAMESPACE = 'users:temp';

    /**
     * Cache Repository instance.
     * 
     * @var Repository
     */
    protected $cache;

    /**
     * User instance
     *
     * @var User
     */
    protected $user;

    public function __construct(Repository $cache, JWTAuth $jwtAuth)
    {
        $this->cache = $cache;
        $this->user = $jwtAuth->toUser($jwtAuth->getToken());
    }

    protected function cacheKey($key)
    {
        return implode(':', [self::USER_CACHE_NAMESPACE, $this->user->id, $key]);
    }

    public function get($key)
    {
        return $this->cache->get($this->cacheKey($key));
    }

    // 1440 = 24 hours * 60 minutes --> cache TTLs for Laravel are in minutes.
    // when the TTL expires, the data won't be returned by the cache service anymore.
    // since it is "temp" data, this should be plenty of time for it to be cached.
    public function put($key, $value, $ttl = 1440)
    {
        $this->cache->put($this->cacheKey($key), $value, $ttl);
    }

}

Then when you actually want to use it:

$userTempStorage = app(\YourApp\Services\UserTempStorage::class);

$userTempStorage->get('latest_uploads', Posts::latest()->take(5)->get()->toArray());

Be careful when storing Eloquent models in a cache -- it can have unpredictable outcomes which usually messes up your data. Either call toArray on the Collection/Model or just store the primary key(s) and fetch the record(s) using Eloquent when you retrieve the value from the cache.

The cache keys would look something like the following if you had a user with an id of 5 and a key of photos: users:temp:5:photos

A word of caution would be to bind a singleton instance into the IoC container for the class above since the constructor calls JWTAuth#toUser which will query your database with the uid claim in the token to find the record of the user who owns the token. You could accomplish that by adding the following to a service provider's register method:

$this->app->singleton(\YourApp\Services\UserTempStorage::class, \YourApp\Services\UserTempStorage::class);

If you want to make it easier on yourself you could bind it to a shorter string such as:

$this->app->singleton('user.storage.temp', \YourApp\Services\UserTempStorage::class);

And then you could have a helper function to make it more like the session() function like this:

function user_temp($key = null, $value = null)
{
    $store = app('user.storage.temp');

    if (is_null($key)) {
        return $store;
    }

    if (!is_null($value)) {
        return $store->set($key, $value);
    }

    return $store->get($key);
}

The null check for the $key param allows you to use it like the session function when passing no args i.e.:

user_temp()->get('photos')

or

user_temp()->set('photos', Photo::latest()->take(3)->get()->toArray());

All 2 comments

I would avoid using session() as it creates a php session which results in a cookie being sent to the client which the server will expect to receive the next time it wants to fetch something specific about the "session" for the user. So if you're writing an API, for example, and you aren't sending back the cookies you receive from the server, your session data won't be available.

As an alternative, you could use a cache service such as memcached or redis -- Laravel has support for both. The benefit of using either of these services is that they can work in a distributed manner if your application/service ever needs to grow beyond more than one server.

I've done something similar in the past so here's something that could get you started:

namespace YourApp\Services;

use YourApp\User;
use Tymon\JWTAuth\JWTAuth;
use Illuminate\Contracts\Cache\Repository;

class UserTempStorage
{

    const USER_CACHE_NAMESPACE = 'users:temp';

    /**
     * Cache Repository instance.
     * 
     * @var Repository
     */
    protected $cache;

    /**
     * User instance
     *
     * @var User
     */
    protected $user;

    public function __construct(Repository $cache, JWTAuth $jwtAuth)
    {
        $this->cache = $cache;
        $this->user = $jwtAuth->toUser($jwtAuth->getToken());
    }

    protected function cacheKey($key)
    {
        return implode(':', [self::USER_CACHE_NAMESPACE, $this->user->id, $key]);
    }

    public function get($key)
    {
        return $this->cache->get($this->cacheKey($key));
    }

    // 1440 = 24 hours * 60 minutes --> cache TTLs for Laravel are in minutes.
    // when the TTL expires, the data won't be returned by the cache service anymore.
    // since it is "temp" data, this should be plenty of time for it to be cached.
    public function put($key, $value, $ttl = 1440)
    {
        $this->cache->put($this->cacheKey($key), $value, $ttl);
    }

}

Then when you actually want to use it:

$userTempStorage = app(\YourApp\Services\UserTempStorage::class);

$userTempStorage->get('latest_uploads', Posts::latest()->take(5)->get()->toArray());

Be careful when storing Eloquent models in a cache -- it can have unpredictable outcomes which usually messes up your data. Either call toArray on the Collection/Model or just store the primary key(s) and fetch the record(s) using Eloquent when you retrieve the value from the cache.

The cache keys would look something like the following if you had a user with an id of 5 and a key of photos: users:temp:5:photos

A word of caution would be to bind a singleton instance into the IoC container for the class above since the constructor calls JWTAuth#toUser which will query your database with the uid claim in the token to find the record of the user who owns the token. You could accomplish that by adding the following to a service provider's register method:

$this->app->singleton(\YourApp\Services\UserTempStorage::class, \YourApp\Services\UserTempStorage::class);

If you want to make it easier on yourself you could bind it to a shorter string such as:

$this->app->singleton('user.storage.temp', \YourApp\Services\UserTempStorage::class);

And then you could have a helper function to make it more like the session() function like this:

function user_temp($key = null, $value = null)
{
    $store = app('user.storage.temp');

    if (is_null($key)) {
        return $store;
    }

    if (!is_null($value)) {
        return $store->set($key, $value);
    }

    return $store->get($key);
}

The null check for the $key param allows you to use it like the session function when passing no args i.e.:

user_temp()->get('photos')

or

user_temp()->set('photos', Photo::latest()->take(3)->get()->toArray());

thanks I麓ll try that!

Was this page helpful?
0 / 5 - 0 ratings