0

I am creating a SPA with vue and laravel. I know i can issue out tokens for every user and store it as a new entry on the database. And from the documentation, I can only list out all the tokens available to a user in hashed format with laravel and the property $token->plainTextToken is not accessible from the eloquent query. I use both normal authentication and sanctum authentication and i sometimes have the need to give back the token to the user. Must i issue out new tokens on every page refresh or is there a way to go about this?

myestery
  • 105
  • 1
  • 11
  • I believe that might not be possible, because the token created is not hashed before saving to DB (plainTextToken is 'id|not-yet-hashed-random-str'). When the token is in use, at that time it is hashed and compared with one on the DB. Check out the [source code][1] and [validation logic][2]. [1]: https://github.com/laravel/sanctum/blob/eb191ddfc3ec04bbead33593bf982e871095f25c/src/HasApiTokens.php#L44 [2]: https://github.com/laravel/sanctum/blob/eb191ddfc3ec04bbead33593bf982e871095f25c/src/Guard.php#L68 – 9paradox Feb 27 '21 at 14:21

3 Answers3

3

I don't know if I understand your question correctly. But do you intend to issue out the token to user after authentication?

The token is stored in the DB as you rightly stated. But what is stored is the hashed copy. The moment you have created the token, you can call the plainTextToken property to get the unhashed copy of the token. This is the one your vue app should send for authorization during each request.

$token = $user->createToken('token-name')->plainTextToken;

This token value is what should be issued out to your vue app to store and use subsequently.

Secondly, the value of $token that will be returned (as at Laravel <= 8.**) may likely contain the id of the table and the unhashed copy of the token. For instance

4|92paqtuqnd92920101ijdkksksn

You are to explode that string and only send the value after the pipe sign. The first value there only shows the id of the table row.

Lastly, I don't understand why the need to issue out new tokens after each page refresh. Maybe I didn't understand your question correctly. But you can simply pass the token back to your vue app in your response, or if it's a synchronous request, you can store it in session and pick it up when you need to.

Mona
  • 31
  • 3
  • 3
    Thanks for your answer.I later discovered that it was hashed one way and the only option is to create a new token – myestery Dec 03 '20 at 12:16
0

there is way i think like bearer token

        $token = null;
        $headers = apache_request_headers();
        if(isset($headers['Authorization'])){
            if (strpos($headers['Authorization'], 'Bearer') !== false) {
                $token = str_replace('Bearer ', '',$headers['Authorization']);
            }
        }

it will return given token

0

Sanctum instructs specifically to use session based auth for SPAs: https://laravel.com/docs/8.x/sanctum#spa-authentication

However, if you want to use tokens, SHA256 is a one way street, and you're never getting plaint text token back from SHA256 hash of it. In your use-case it should simply be kept within the vue storage you're using. E.g. with pinia, you could setup login store to keep the token there.

An answer to a similar question follows as I didn't read the full question at first. Not really relevant to SPAs, but could be useful for someone who was looking for a literal answer to the literal question: "can I make Sanctum store plaintext tokens for later retrieval for me?"

This is how I've done it:

  1. Override HasApiTokens::createToken() by creating HasStorableApiTokens trait like so:
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use Laravel\Sanctum\HasApiTokens;
use Laravel\Sanctum\NewAccessToken;

trait HasStorableApiTokens
{
    use HasApiTokens;

    public function createToken(string $name, array $abilities = ['*'], $store = false)
    {
        $plainTextToken = Str::random(40);
        $token          = $this->tokens()->create([
            'name'       => $name,
            'token'      => hash('sha256', $plainTextToken),
            'kept_token' => $store ? $plainTextToken : null,
            'abilities'  => $abilities,
        ]);

        return new NewAccessToken($token, $token->getKey() . '|' . $plainTextToken);
    }
}

anything you'd like to issue these storable tokens for needs to use this new trait instead of the original one. You also have to create a corresponding migration to create kept_token column on personal_access_tokens table.

  1. Override default model as per https://laravel.com/docs/8.x/sanctum#overriding-default-models like so:
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;

class PersonalAccessToken extends SanctumPersonalAccessToken
{
    protected $fillable = [
        'name',
        'token',
        'kept_token',
        'abilities',
    ];

    protected $casts = [
        'abilities'    => 'json',
        'last_used_at' => 'datetime',
        'kept_token'   => 'encrypted',
    ];
}

and tell Sanctum to use it instead of the original one. I've done it in AuthServiceProvider::boot() which looks like

public function boot()
{
    $this->registerPolicies();
    Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}

for me.

Note: you have to have encryption set up for the above to work: https://laravel.com/docs/8.x/encryption#main-content .

leevanoetz
  • 157
  • 1
  • 8