<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddFirstPartyToOauthClients extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('oauth_clients', function (Blueprint $table) {
$table->boolean('first_party_client')->after('revoked')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('oauth_clients', function (Blueprint $table) {
$table->dropColumn('first_party_client');
});
}
}
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'grant_types' => 'array',
'personal_access_client' => 'bool',
'password_client' => 'bool',
'revoked' => 'bool',
'first_party_client' => 'bool',
];
<?php
namespace Laravel\Passport\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Passport\Passport;
use Laravel\Passport\Bridge\User;
use Laravel\Passport\TokenRepository;
use Laravel\Passport\ClientRepository;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response as Psr7Response;
use League\OAuth2\Server\AuthorizationServer;
use Illuminate\Contracts\Routing\ResponseFactory;
class AuthorizationController
{
use HandlesOAuthErrors;
/**
* The authorization server.
*
* @var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* The response factory implementation.
*
* @var \Illuminate\Contracts\Routing\ResponseFactory
*/
protected $response;
/**
* The Token Repository
* @param \Laravel\Passport\TokenRepository $tokens
*/
protected $tokens;
/**
* Create a new controller instance.
*
* @param \League\OAuth2\Server\AuthorizationServer $server
* @param \Illuminate\Contracts\Routing\ResponseFactory $response
* @param \Laravel\Passport\TokenRepository $tokens
*
* @return void
*/
public function __construct(AuthorizationServer $server, ResponseFactory $response, TokenRepository $tokens)
{
$this->server = $server;
$this->response = $response;
$this->tokens = $tokens;
}
/**
* Authorize a client to access the user's account.
*
* @param \Psr\Http\Message\ServerRequestInterface $psrRequest
* @param \Illuminate\Http\Request $request
* @param \Laravel\Passport\ClientRepository $clients
* @return \Illuminate\Http\Response
*/
public function authorize(
ServerRequestInterface $psrRequest,
Request $request,
ClientRepository $clients
) {
return $this->withErrorHandling(function () use ($psrRequest, $request, $clients) {
$authRequest = $this->server->validateAuthorizationRequest($psrRequest);
$user = $request->user();
$client = $clients->find($authRequest->getClient()->getIdentifier());
if (
$client->first_party_client || ($this->hasValidToken($user, $client, $scopes = $this->parseScopes($authRequest)))
) {
return $this->approveRequest($authRequest, $user);
}
$request->session()->put('authRequest', $authRequest);
return $this->response->view('passport::authorize', [
'client' => $client,
'user' => $user,
'scopes' => $scopes,
'request' => $request,
]);
});
}
/**
* Transform the authorization requests's scopes into Scope instances.
*
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
* @return array
*/
protected function parseScopes($authRequest)
{
return Passport::scopesFor(
collect($authRequest->getScopes())->map(function ($scope) {
return $scope->getIdentifier();
})->unique()->all()
);
}
/**
* Approve the authorization request.
*
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
* @param \Illuminate\Database\Eloquent\Model $user
* @return \Illuminate\Http\Response
*/
protected function approveRequest($authRequest, $user)
{
$authRequest->setUser(new User($user->getKey()));
$authRequest->setAuthorizationApproved(true);
return $this->convertResponse(
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
);
}
/**
* Check if user has an previous valid token for the same client.
*
* @param \Illuminate\Database\Eloquent\Model $user
* @param \Laravel\Passport\Client $client
* @param array $scopes
* @return boolean
*/
protected function hasValidToken($user, $client, $scopes)
{
$token = $this->tokens->findValidToken($user, $client);
return $token && $token->scopes === collect($scopes)->pluck('id')->all();
}
}
protected $signature = 'passport:client
{--personal : Create a personal access token client}
{--password : Create a password grant client}
{--client : Create a client credentials grant client}
{--name= : The name of the client}
{--redirect_uri= : The URI to redirect to after authorization }
{--user_id= : The user ID the client should be assigned to }';
{--user_id= : The user ID the client should be assigned to }
{--first_party : The client will be marked as First Party (No Authentication Screen) }';
/**
* Create a authorization code client.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
protected function createAuthCodeClient(ClientRepository $clients)
{
$userId = $this->option('user_id') ?: $this->ask(
'Which user ID should the client be assigned to?'
);
$name = $this->option('name') ?: $this->ask(
'What should we name the client?'
);
$redirect = $this->option('redirect_uri') ?: $this->ask(
'Where should we redirect the request after authorization?',
url('/auth/callback')
);
$first_party = $this->option('first_party') ?: $this->confirm(
'Is this client a First Party?'
);
$client = $clients->create(
$userId, $name, $redirect
$userId,
$name,
$redirect,
false,
false,
$first_party
);
/**
* Store a new client.
*
* @param int $userId
* @param string $name
* @param string $redirect
* @param bool $personalAccess
* @param bool $password
* @param bool $firstParty
* @return \Laravel\Passport\Client
*/
public function create($userId, $name, $redirect, $personalAccess = false, $password = false, $firstParty = false)
{
$client = Passport::client()->forceFill([
'user_id' => $userId,
'name' => $name,
'secret' => Str::random(40),
'redirect' => $redirect,
'personal_access_client' => $personalAccess,
'password_client' => $password,
'revoked' => false,
'first_party_client' => $firstParty,
]);
$client->save();
return $client;
}