Skip to content

Commit cd375fa

Browse files
Added custom auth token header support (#354)
* Addded custom auth token header support * formatting * formatting Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 95da597 commit cd375fa

File tree

3 files changed

+167
-1
lines changed

3 files changed

+167
-1
lines changed

src/Guard.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function __invoke(Request $request)
6161
}
6262
}
6363

64-
if ($token = $request->bearerToken()) {
64+
if ($token = $this->getTokenFromRequest($request)) {
6565
$model = Sanctum::$personalAccessTokenModel;
6666

6767
$accessToken = $model::findToken($token);
@@ -105,6 +105,21 @@ protected function supportsTokens($tokenable = null)
105105
));
106106
}
107107

108+
/**
109+
* Get the token from the request.
110+
*
111+
* @param \Illuminate\Http\Request $request
112+
* @return string|null
113+
*/
114+
protected function getTokenFromRequest(Request $request)
115+
{
116+
if (is_callable(Sanctum::$accessTokenRetrievalCallback)) {
117+
return (string) (Sanctum::$accessTokenRetrievalCallback)($request);
118+
}
119+
120+
return $request->bearerToken();
121+
}
122+
108123
/**
109124
* Determine if the provided access token is valid.
110125
*

src/Sanctum.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ class Sanctum
1313
*/
1414
public static $personalAccessTokenModel = 'Laravel\\Sanctum\\PersonalAccessToken';
1515

16+
/**
17+
* A callback that can get the token from the request.
18+
*
19+
* @var callable|null
20+
*/
21+
public static $accessTokenRetrievalCallback;
22+
1623
/**
1724
* A callback that can add to the validation of the access token.
1825
*
@@ -83,6 +90,17 @@ public static function usePersonalAccessTokenModel($model)
8390
static::$personalAccessTokenModel = $model;
8491
}
8592

93+
/**
94+
* Specify a callback that should be used to fetch the access token from the request.
95+
*
96+
* @param callable $callback
97+
* @return void
98+
*/
99+
public static function getAccessTokenFromRequestUsing(callable $callback)
100+
{
101+
static::$accessTokenRetrievalCallback = $callback;
102+
}
103+
86104
/**
87105
* Specify a callback that should be used to authenticate access tokens.
88106
*

tests/GuardTest.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,139 @@ public function test_authentication_fails_if_callback_returns_false()
280280

281281
$user = $requestGuard->setRequest($request)->user();
282282
$this->assertNull($user);
283+
284+
Sanctum::$accessTokenAuthenticationCallback = null;
285+
}
286+
287+
public function test_authentication_is_successful_with_token_in_custom_header()
288+
{
289+
$this->loadLaravelMigrations(['--database' => 'testbench']);
290+
$this->artisan('migrate', ['--database' => 'testbench'])->run();
291+
292+
$factory = Mockery::mock(AuthFactory::class);
293+
294+
$guard = new Guard($factory, null);
295+
296+
$webGuard = Mockery::mock(stdClass::class);
297+
298+
$factory->shouldReceive('guard')
299+
->with('web')
300+
->andReturn($webGuard);
301+
302+
$webGuard->shouldReceive('user')->once()->andReturn(null);
303+
304+
$request = Request::create('/', 'GET');
305+
$request->headers->set('X-Auth-Token', 'test');
306+
307+
$user = User::forceCreate([
308+
'name' => 'Taylor Otwell',
309+
'email' => 'taylor@laravel.com',
310+
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
311+
'remember_token' => Str::random(10),
312+
]);
313+
314+
$token = PersonalAccessToken::forceCreate([
315+
'tokenable_id' => $user->id,
316+
'tokenable_type' => get_class($user),
317+
'name' => 'Test',
318+
'token' => hash('sha256', 'test'),
319+
]);
320+
321+
Sanctum::getAccessTokenFromRequestUsing(function (Request $request) {
322+
return $request->header('X-Auth-Token');
323+
});
324+
325+
$returnedUser = $guard->__invoke($request);
326+
327+
$this->assertEquals($user->id, $returnedUser->id);
328+
$this->assertEquals($token->id, $returnedUser->currentAccessToken()->id);
329+
$this->assertInstanceOf(DateTimeInterface::class, $returnedUser->currentAccessToken()->last_used_at);
330+
331+
Sanctum::$accessTokenRetrievalCallback = null;
332+
}
333+
334+
public function test_authentication_fails_with_token_in_authorization_header_when_using_custom_header()
335+
{
336+
$this->loadLaravelMigrations(['--database' => 'testbench']);
337+
$this->artisan('migrate', ['--database' => 'testbench'])->run();
338+
339+
$factory = Mockery::mock(AuthFactory::class);
340+
341+
$guard = new Guard($factory, null);
342+
343+
$webGuard = Mockery::mock(stdClass::class);
344+
345+
$factory->shouldReceive('guard')
346+
->with('web')
347+
->andReturn($webGuard);
348+
349+
$webGuard->shouldReceive('user')->once()->andReturn(null);
350+
351+
$request = Request::create('/', 'GET');
352+
$request->headers->set('Authorization', 'Bearer test');
353+
354+
$user = User::forceCreate([
355+
'name' => 'Taylor Otwell',
356+
'email' => 'taylor@laravel.com',
357+
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
358+
'remember_token' => Str::random(10),
359+
]);
360+
361+
$token = PersonalAccessToken::forceCreate([
362+
'tokenable_id' => $user->id,
363+
'tokenable_type' => get_class($user),
364+
'name' => 'Test',
365+
'token' => hash('sha256', 'test'),
366+
]);
367+
368+
Sanctum::getAccessTokenFromRequestUsing(function (Request $request) {
369+
return $request->header('X-Auth-Token');
370+
});
371+
372+
$returnedUser = $guard->__invoke($request);
373+
374+
$this->assertNull($returnedUser);
375+
376+
Sanctum::$accessTokenRetrievalCallback = null;
377+
}
378+
379+
public function test_authentication_fails_with_token_in_custom_header_when_using_default_authorization_header()
380+
{
381+
$this->loadLaravelMigrations(['--database' => 'testbench']);
382+
$this->artisan('migrate', ['--database' => 'testbench'])->run();
383+
384+
$factory = Mockery::mock(AuthFactory::class);
385+
386+
$guard = new Guard($factory, null);
387+
388+
$webGuard = Mockery::mock(stdClass::class);
389+
390+
$factory->shouldReceive('guard')
391+
->with('web')
392+
->andReturn($webGuard);
393+
394+
$webGuard->shouldReceive('user')->once()->andReturn(null);
395+
396+
$request = Request::create('/', 'GET');
397+
$request->headers->set('X-Auth-Token', 'test');
398+
399+
$user = User::forceCreate([
400+
'name' => 'Taylor Otwell',
401+
'email' => 'taylor@laravel.com',
402+
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
403+
'remember_token' => Str::random(10),
404+
]);
405+
406+
$token = PersonalAccessToken::forceCreate([
407+
'tokenable_id' => $user->id,
408+
'tokenable_type' => get_class($user),
409+
'name' => 'Test',
410+
'token' => hash('sha256', 'test'),
411+
]);
412+
413+
$returnedUser = $guard->__invoke($request);
414+
415+
$this->assertNull($returnedUser);
283416
}
284417

285418
protected function getPackageProviders($app)

0 commit comments

Comments
 (0)