Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ctyler's avatar

Passport API Machine to Machine Tokens

Hello, I have two applications. One on the local network that syncs data with our Active Directory and one that is remote. I am syncing data between them using the API. The remote application is for emergency notification to our employees (power outages etc.)

As part of the syncing process when a new person is added to the local database it is added to the remote over the api. I am currently using passport and I set it up using php artisan passport:client –client

It is working but I think I am missing a step.

// This is athe testing server
$options = ['verify' => false];
    $response = Http::withOptions($options)->asForm()->post(config('notify.url') .'/oauth/token', [
        'grant_type' => 'client_credentials',
        'client_id' => '1',
        'client_secret' => 'ghdfghdfghdghdghghdtyertyetdfghdghd',
        'scope' => '*',
    ]);

$token = $response->json()['access_token'];

    $response = Http::withOptions($options)
        ->withToken($token)
        ->get(config('notify.url') . '/users');

The problem is each time I hit the config('notify.url') .'/oauth/token it adds a row to the oauth_access_token table. Each row has its own expires_at.

This seem to me that I need to visit 'oauth/token' and then stores the token. Then keep using that until it is used and the response from the remote application indicates it is expired - then hit the 'oauth/token' url again for a new token and then store that.

Is that how the work flow should go or am I missing something?

0 likes
7 replies
martinbean's avatar

@ctyler Well yeah, if you just keep requesting new tokens on each request, then that’s going to generate a new token and create a row in your database.

So, as you say yourself: request a token, store it. You’ll also get a refresh token and expires at. Store those, too. Then have a scheduled task that automatically refreshes any access tokens in your database, and use the stored access token in the database for subsequent requests.

2 likes
ctyler's avatar

Thank you for the fast replay @martinbean

Sorry for the noob questions. This is my first time swimming in the API end of the pool.

So, when I send the request for the token, I don't seem to be getting back a refresh token:

{
    "token_type": "Bearer",
    "expires_in": 31536000,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiZTRjNjhjZmI5MTUxMWExZjZlYzA2NmMxNmNmNDhmNjIzZTljOWQ0ZDBkMmUzMTI5Yjk0ODNhODFhNmUzMGVhMWE3YWU4NWU3NjNhZmFkYjYiLCJpYXQiOjE2Mjg1MTMyNDcsIm5iZiI6MTYyODUxMzI0NywiZXhwIjoxNjYwMDQ5MjQ3LCJzdWIiOiIiLCJzY29wZXMiOlsiKiJdfQ.292S6vFYWoB4ZGvEQ-3w8pciiShajoOR4JSD3wnK3eJOPc4XMmQpSpwLG9BvkIOamcKWX6fij2v8eQGlyC1gByax4ZooU1J5pPLwasNWSnnfBB2jMbAWdFC3hSfmDnQbEFbZI_EA5nE-Oali78m1YQtvgbAhBr7aSMN2LsmUX5EFCG09lX2zbgEz1bmbLzJwHHFy_JL1Owb5UscwIeaTXZ3nfv--nuddHFkPHiaxzliVTZRwD34lr-C_ph8X3rTiC3T568c3igB66lAOilVlWqIRHyuFEMJcb0N452xzC-C5Yp0q96cVTQpfoCRRRkLZ8-vh-mFwLin2oDNo1USnyevWmWMsH6dim2Hcw2IMX5H4_IDvIJxXSoUtV0jV5bzTaYs1ufikCbMy7mCLp-jQMvRi5u8W0myD2LQ_SoNQRlNxj-a2j71EfTTYrnqVWBP_hd2igFSf1yW3jTnurNSMXiK5hNSAP6K1YOnhvm4Eiu7s3jEgKnlEXdWaZEmElhT9o-Q_kQac_hrPGIYRShFtyz8D8UYgy9hBNjwWGeNt2rRk2Fnpg5ZWfPVIA0QrUKEtr-t52ysvh377FuUZCyez-BayXO1rRa8ix1nAB7e9oDkKU6aM4NPrdFeluGsdy9FIU2L2mFH6gauXhpe4tegQXpTFY-iIfgbc0pps0iUSUQk"
}

I thought it might be because I only have

Passport::routes();

in my AuthServiceProvider but I also added

Passport::tokensExpireIn(now()->addDays(15));

Still no refresh token

Theraloss's avatar
Level 1

It's easier than that: use Cache. You can use a combination of getand put to retrieve the token from your cache or, if it doesn't exist (or is expired), you will fetch a new one. You can't use Cache::remember because your "expiration time" will be in the HTTP response and therefore you don't have access to it before making that call.

An example:

public function getM2MToken(): string
{
	$cacheKey = 'm2m_token';
	$token = Cache::get($cacheKey);

	if (is_null($token)) {
		$token = Http::post()->json(); // Your client_credentials flow

		Cache::put($cacheKey, $token['access_token'], $token['expires_in']);
	}

	return $token;
}

Note that the Client Credentials will never return a refresh token, so you need to retrieve a new one when the previous one expires.

1 like
martinbean's avatar

@ctyler If you get an expires_in value then you can use that for caching the access token. I‘d deduct a few seconds though to account for HTTP latency.

ctyler's avatar

Hi Martin, What is the best way to do that? Is it as simple as something like

Cache::put($cacheKey, $token['access_token'], $token['expires_in']-5);

Please or to participate in this conversation.