Skip to content

Instantly share code, notes, and snippets.

@ryzr
Last active August 15, 2018 06:34
Show Gist options
  • Save ryzr/bb897bd00967007f6a3ee6c201d19187 to your computer and use it in GitHub Desktop.
Save ryzr/bb897bd00967007f6a3ee6c201d19187 to your computer and use it in GitHub Desktop.
Custom Api Authorization
<?php
Route::post('register', 'ApiAuthorizationController@register');
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Laravel\Passport\Bridge\AccessToken;
use Laravel\Passport\Bridge\AccessTokenRepository;
use Laravel\Passport\Bridge\ClientRepository;
use Laravel\Passport\Client;
use Laravel\Passport\Passport;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
use Zend\Diactoros\Response as Psr7Response;
class ApiAuthorizationController extends Controller
{
/**
* @var \Laravel\Passport\Bridge\AccessTokenRepository
*/
protected $accessTokenRepository;
/**
* @var \Laravel\Passport\Bridge\ClientRepository;
*/
protected $clientRepository;
public function __construct(AccessTokenRepository $accessTokenRepository, ClientRepository $clientRepository)
{
$this->accessTokenRepository = $accessTokenRepository;
$this->clientRepository = $clientRepository;
}
public function register(TokenRepository $tokens, Request $request)
{
$user = User::firstOrCreate(['email' => $request->input('email')], [
'name' => $request->input('name'),
]);
$clientIdentifier = env("API_CLIENT_ID");
$client = Client::find($clientIdentifier);
$accessToken = $this->generateAccessToken($client, $user->id);
if ($apiToken = $tokens->getValidToken($user, $client)) {
$accessToken->setIdentifier($apiToken->id);
$accessToken->setExpiryDateTime($apiToken->expires_at);
} else {
$accessToken = $this->generateNewApiToken($accessToken);
}
return $this->generateApiResponse($accessToken);
}
protected function generateAccessToken(Client $client, $userIdentifier)
{
$clientEntity = $this->clientRepository->getClientEntity($client->id, 'password', $client->secret);
$accessToken = $this->accessTokenRepository->getNewToken($clientEntity, [], $userIdentifier);
$accessToken->setClient($clientEntity);
$accessToken->setUserIdentifier($userIdentifier);
$accessToken->setExpiryDateTime((new \DateTime())->add(Passport::tokensExpireIn()));
$accessToken->addScope(new \Laravel\Passport\Bridge\Scope('*'));
return $accessToken;
}
protected function generateNewApiToken(AccessToken $accessToken)
{
$maxGenerationAttempts = 10;
while ($maxGenerationAttempts-- > 0) {
$accessToken->setIdentifier($this->generateUniqueIdentifier());
try {
$this->accessTokenRepository->persistNewAccessToken($accessToken);
return $accessToken;
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
if ($maxGenerationAttempts === 0) {
throw $e;
}
}
}
}
protected function generateApiResponse(AccessToken $accessToken)
{
$bearerResponse = new BearerTokenResponse();
$bearerResponse->setAccessToken($accessToken);
$bearerResponse->setPrivateKey(new CryptKey(Passport::keyPath('oauth-private.key'), null, false));
$bearerResponse->setEncryptionKey(app('encrypter')->getKey());
$psrResponse = $bearerResponse->generateHttpResponse(new Psr7Response());
return new Response(
$psrResponse->getBody(),
$psrResponse->getStatusCode(),
$psrResponse->getHeaders()
);
}
/**
* Generate a new unique identifier.
*
* @param int $length
*
* @throws OAuthServerException
*
* @return string
*/
protected function generateUniqueIdentifier($length = 40)
{
try {
return bin2hex(random_bytes($length));
// @codeCoverageIgnoreStart
} catch (\TypeError $e) {
throw OAuthServerException::serverError('An unexpected error has occurred');
} catch (\Error $e) {
throw OAuthServerException::serverError('An unexpected error has occurred');
} catch (\Exception $e) {
// If you get this message, the CSPRNG failed hard.
throw OAuthServerException::serverError('Could not generate a random string');
}
// @codeCoverageIgnoreEnd
}
}
window.Vue = require('vue');
const app = new Vue({
el: '#app',
data: {
name: '',
email: '',
accessToken: localStorage.getItem('accessToken'),
},
watch: {
accessToken(accessToken) {
localStorage.setItem('accessToken', accessToken);
axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
},
},
computed: {
isLoggedIn() {
return !!this.accessToken;
},
},
mounted() {
if (this.isLoggedIn) {
axios.defaults.headers.common['Authorization'] = `Bearer ${this.accessToken}`;
this.getUser();
}
},
methods: {
async getUser() {
const response = await axios.get('/api/user');
this.name = response.data.name;
this.email = response.data.email;
console.log(response);
return response;
},
async register() {
const response = await axios.post('/api/register', {
email: this.email,
name: this.name,
});
this.accessToken = response.data.access_token;
this.getUser();
},
},
});
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" value="{{ csrf_token() }}">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet" type="text/css">
<link href="/css/app.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id="app" class="flex-center position-ref full-height">
<div class="content">
<div class="d-flex">
<input @keyup.enter="register" type="text" v-model="name" class="form-control" />
<input @keyup.enter="register" type="email" v-model="email" class="form-control" />
<button @click.prevent="register" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
<script src="/js/app.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment