First important information: I’m new to Laravel, so your patience is appreciated.
I’m currently migrating a framework of mine to Laravel and still in the early stages. I know that Laravel has it’s own database construction mechanism that is recommended to use the migrations and the Models, however, for my purpose, I’d like to use my own database that I use in other systems that I’ve built in the past. The idea for this system is to have a shared database, but operable through different tech stacks.
This is my current scenario:
- Laravel 8
- Sanctum 2.14
Frontend (Laravel):
- I’ve built a very simple login page that has a controller and sends data (user and password) to my backend (Laravel). In the backend (different server), I grab the data and check if the data is correct. Being correct, I send a json response with some data, like:
returnStatus = true
loginVerification = true
IDCrypt = asdfasd4fa654sd54a (encrypted ID to grab in the frontend again)
Up till here, it’s working fine, as I wanted and very similar to my legacy systems.
My idea would be to get this response in the frontend, via auth token managed by Sanctum and use a middleware to check the token in order to let the user access some web routes.
I’ve watched some videos, but I’m only finding videos that use all the database mechanism that Laravel provides.
However, my intention would be to generate the token with data from my own table and data objects I created (without any existing Laravel´s models).
- Is there a way for me to do this?
- How would I set the token in the backend and include in my response?
- How would I grab the token in the frontend in a secure way?
Edit – Progress on creating the Legacy User.
I´m following @gavin´s suggestion. So far, my Legacy User looks like this:
<?php
namespace AppModels;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use LaravelSanctumHasApiTokens;
class LegacyUser extends Authenticatable
{
use HasFactory, HasApiTokens;
/**
* Build content placeholder body.
* @return array
*/
public function cphBodyBuild($oudRecordParameters): array
{
// Variables.
// ----------------------
$arrReturn = ['returnStatus' => false];
// ----------------------
// Logic.
try {
// Build object - details.
if ($this->oudRecordParameters !== null) {
$oudRecord = new SyncSystemNSObjectUsersDetails($oudRecordParameters);
$arrReturn['oudRecord'] = $oudRecord->recordDetailsGet(0, 1);
if ($arrReturn['oudRecord']['returnStatus'] === true) {
$arrReturn['returnStatus'] = true;
}
}
} catch (Error $cphBodyBuildError) {
if ($GLOBALS['configDebug'] === true) {
throw new Error('cphBodyBuildError: ' . $cphBodyBuildError->message());
}
} finally {
//
}
return $arrReturn;
}
}
I´m not sure how to override the methods he mentioned (createToken and tokens). As of now, when I use:
$userLogin = new LegacyUser();
$userLoginData = $userLogin->cphBodyBuild($param);
$userLoginToken = $userLogin->createToken('testing_token')->plainTextToken;
It logs the following error:
[previous exception] [object] (PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'tokenable_id' cannot be null at …
[stacktrace]
Edit – Developed createToken method.
After further research on @gavin´s suggestion, I found this post that helped me make some progress on overriding the createToken method:
Why does one need to pass a string in the createToken method?
So, in my LagacyUser model, I created the following method:
/**
* Override createToken method.
*/
public function createToken(string $name, array $abilities = ['*'])
{
$token = $this->tokens()->create([
'name' => $name,
'token' => hash('sha256', $plainTextToken = Str::random(80)),
'abilities' => $abilities,
]);
return new NewAccessToken($token, $token->id.'|'.$plainTextToken);
}
It´s still returning me the error:
[previous exception] [object] (PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'tokenable_id' cannot be null at …
[stacktrace]
I found another post that also helped me try to figure out how I need to change the tokens method:
Laravel Sanctum with uuid column in User model doesn't save tokenable_id
Something like this:
public function tokens()
{
return $this->morphMany(Sanctum::$personalAccessTokenModel, 'tokenable', ‘tokenable_type’, ‘tokenable_id’);
}
However, I still have no idea how to convert tokenable_id into my model’s ID.
Remember: I´m not using Laravel migrations and all their wired up classes.
Note: Opened to Laravel Passport solution.
2
Answers
Turned out that I didn’t need to override the createToken() and tokens() methods. As my Laravel experience is low, I didn’t know how to set the Laravel native ID attribute in my custom model. (That’s also part of the reason I wanted to build this without the wired up Laravel models – to deepen my learnings)
In order to learn how to set the ID attribute, I found this post: https://stackoverflow.com/a/17236014
And the code ended up looking like this:
And creating the token looks like this:
After the createToken method is called, a new record in
personal_access_tokens
is created.Lets say you have a model
LegacyUser
and this is your existing authenticable entity.In this model simply override methods defined in the
LaravelSanctumHasApiTokens
trait. SpecificallycreateToken
and thetokens
relation for your use case by the sounds.Then you can create tokens anywhere like usual with
Then us the token as usual.
NOTE: if you’re also changing how the tokens are stored/retrieved you’ll need to set the token model, docs cover that here: https://laravel.com/docs/8.x/sanctum#overriding-default-models
If you want to avoid using authenticable entites (ie, no laravel models) entirely that’s going to be more complicated and Passport might be a better shout, as
client_credentials
dont need to be associated to a user entity.Alternatively: Write your own middleware that is compatbile with your existing auth process.