├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── Dockerfile.composer ├── LICENSE ├── README.md ├── composer.json ├── docker-compose.yml └── src ├── Auth └── User.php ├── MongodbPassportServiceProvider.php └── Passport ├── AuthCode.php ├── Bridge ├── RefreshToken.php └── RefreshTokenRepository.php ├── Client.php ├── PersonalAccessClient.php ├── PersonalAccessTokenFactory.php ├── RefreshToken.php └── Token.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.project 2 | *.sublime-project 3 | *.sublime-workspace 4 | .DS_Store 5 | .idea/ 6 | composer.lock 7 | composer.phar 8 | phpunit.phar 9 | vendor 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-mongodb-passport` will be documented in this file 4 | 5 | ## 1.1.4 - 2018-08-13 6 | - add support for passport 7 7 | 8 | ## 1.1.3 - 2018-04-24 9 | - add support for passport 6 10 | 11 | ## 1.1.2 - 2018-03-22 12 | - fix support for laravel-framework 5.6, laravel-passport 5, laravel-mongodb 3.4 13 | 14 | ## 1.1.1 - 2018-01-22 15 | - fix lumen support 16 | 17 | ## 1.1.0 - 2018-01-11 18 | - transfer ownership to designmynight 19 | 20 | ## 1.0.1 - 2018-01-11 21 | - add friendly User class implementation 22 | 23 | ## 1.0.0 - 2018-01-10 24 | - initial release 25 | -------------------------------------------------------------------------------- /Dockerfile.composer: -------------------------------------------------------------------------------- 1 | FROM designmynight/php7.1-cli-mongo 2 | 3 | WORKDIR /opt 4 | 5 | RUN apk add --no-cache libpng libpng-dev && docker-php-ext-install gd && apk del libpng-dev 6 | 7 | RUN docker-php-ext-install pcntl 8 | 9 | COPY --from=composer:1.6 /usr/bin/composer /usr/bin/composer 10 | 11 | RUN /usr/bin/composer global require hirak/prestissimo 12 | 13 | COPY composer.json /opt 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 DesignMyNight 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Laravel MongoDB Passport 2 | =============== 3 | 4 | [![Latest Stable Version](http://img.shields.io/github/release/designmynight/laravel-mongodb-passport.svg)](https://packagist.org/packages/designmynight/laravel-mongodb-passport) [![Total Downloads](http://img.shields.io/packagist/dm/designmynight/laravel-mongodb-passport.svg)](https://packagist.org/packages/designmynight/laravel-mongodb-passport) 5 | 6 | A service provider to add support for [Laravel Passport](https://github.com/laravel/passport) and [MongoDB](https://github.com/jenssegers/laravel-mongodb). 7 | 8 | Table of contents 9 | ----------------- 10 | * [Installation](#installation) 11 | 12 | Installation 13 | ------------ 14 | 15 | Installation using composer: 16 | 17 | ```sh 18 | composer require designmynight/laravel-mongodb-passport 19 | ``` 20 | 21 | You need to have your `App\User` class extend `DesignMyNight\Mongodb\Auth\User.php` instead of the default `Illuminate\Foundation\Auth\User`. This user class extends larvel-mongodb eloquent user as well as adding all the standard and required authentication and laravel passport traits. 22 | 23 | ```php 24 | register(DesignMyNight\Mongodb\MongodbPassportServiceProvider::class); 56 | ``` 57 | 58 | The service provider will overide the default laravel passport models in order to use mongodb's implementation of eloquent. There is no need to register any additional classes or add any additional configuration other than those outlined in [Laravel Passport](https://github.com/laravel/passport) and [MongoDB](https://github.com/jenssegers/laravel-mongodb). 59 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "designmynight/laravel-mongodb-passport", 3 | "description": "A package to allow laravel/passport use with jenssegers/laravel-mongodb", 4 | "homepage": "https://github.com/designmynight/laravel-mongodb-passport", 5 | "license": "MIT", 6 | "keywords": [ 7 | "laravel", 8 | "laravel-mongodb", 9 | "laravel-mongodb-passport", 10 | "laravel-passport", 11 | "mongodb", 12 | "passport", 13 | "designmynight" 14 | ], 15 | "require": { 16 | "php": ">=7.1", 17 | "illuminate/support": "^5.5 || ^6.0", 18 | "jenssegers/mongodb": "3.3.* || 3.4.* || 3.5.* || 3.6.* || 4.0.* || 5.0.* || 6.0.*", 19 | "laravel/passport": "6.0.* || 7.0.* || 7.4.* || 7.5.* || ^8.0 || ^9.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "DesignMyNight\\Mongodb\\": "src" 24 | } 25 | }, 26 | "authors": [ 27 | { 28 | "name": "DesignMyNight", 29 | "email": "support@designmynight.com", 30 | "role": "Support" 31 | } 32 | ], 33 | "extra": { 34 | "laravel": { 35 | "providers": [ 36 | "DesignMyNight\\Mongodb\\MongodbPassportServiceProvider" 37 | ] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | composer: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile.composer 7 | command: composer -o install 8 | volumes: 9 | - .:/opt 10 | working_dir: /opt 11 | -------------------------------------------------------------------------------- /src/Auth/User.php: -------------------------------------------------------------------------------- 1 | app->bind(PassportRefreshTokenRepository::class, function () { 28 | return $this->app->make(RefreshTokenRepository::class); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Passport/AuthCode.php: -------------------------------------------------------------------------------- 1 | 'bool', 30 | ]; 31 | 32 | /** 33 | * The attributes that should be mutated to dates. 34 | * 35 | * @var array 36 | */ 37 | protected $dates = [ 38 | 'expires_at', 39 | ]; 40 | 41 | /** 42 | * Get the client that owns the authentication code. 43 | * 44 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 45 | */ 46 | public function client() 47 | { 48 | return $this->hasMany(Client::class); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Passport/Bridge/RefreshToken.php: -------------------------------------------------------------------------------- 1 | 'bool', 23 | ]; 24 | 25 | /** 26 | * @var string[] 27 | */ 28 | protected $dates = ['expires_at']; 29 | 30 | /** 31 | * @var array 32 | */ 33 | protected $guarded = []; 34 | 35 | /** 36 | * @var bool 37 | */ 38 | public $incrementing = false; 39 | 40 | /** 41 | * @var string 42 | */ 43 | protected $primaryKey = 'id'; 44 | 45 | /** 46 | * @var string 47 | */ 48 | protected $table = 'oauth_refresh_tokens'; 49 | 50 | /** 51 | * @var bool 52 | */ 53 | public $timestamps = false; 54 | } 55 | -------------------------------------------------------------------------------- /src/Passport/Bridge/RefreshTokenRepository.php: -------------------------------------------------------------------------------- 1 | database->table('oauth_refresh_tokens') 29 | ->where('id', $tokenId)->first(); 30 | 31 | return $refreshToken === null || $refreshToken['revoked']; 32 | } 33 | 34 | /** 35 | * @param RefreshToken|RefreshTokenEntityInterface $refreshTokenEntity 36 | */ 37 | public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity) 38 | { 39 | $refreshTokenEntity->newModelQuery()->create([ 40 | 'id' => $id = $refreshTokenEntity->getIdentifier(), 41 | 'access_token_id' => $accessTokenId = $refreshTokenEntity->getAccessToken()->getIdentifier(), 42 | 'revoked' => false, 43 | 'expires_at' => $refreshTokenEntity->getExpiryDateTime(), 44 | ]); 45 | 46 | $this->events->dispatch(new RefreshTokenCreated($id, $accessTokenId)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Passport/Client.php: -------------------------------------------------------------------------------- 1 | 'bool', 39 | 'password_client' => 'bool', 40 | 'revoked' => 'bool', 41 | ]; 42 | 43 | /** 44 | * Get all of the authentication codes for the client. 45 | * 46 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 47 | */ 48 | public function authCodes() 49 | { 50 | return $this->hasMany(AuthCode::class); 51 | } 52 | 53 | /** 54 | * Get all of the tokens that belong to the client. 55 | * 56 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 57 | */ 58 | public function tokens() 59 | { 60 | return $this->hasMany(Token::class); 61 | } 62 | 63 | /** 64 | * Determine if the client is a "first party" client. 65 | * 66 | * @return bool 67 | */ 68 | public function firstParty() 69 | { 70 | return $this->personal_access_client || $this->password_client; 71 | } 72 | 73 | /** 74 | * Determine if the client should skip the authorization prompt. 75 | * 76 | * @return bool 77 | */ 78 | public function skipsAuthorization() 79 | { 80 | return false; 81 | } 82 | 83 | /** 84 | * Determine if the client is a confidential client. 85 | * 86 | * @return bool 87 | */ 88 | public function confidential() 89 | { 90 | return ! empty($this->secret); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Passport/PersonalAccessClient.php: -------------------------------------------------------------------------------- 1 | belongsTo(Client::class); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Passport/PersonalAccessTokenFactory.php: -------------------------------------------------------------------------------- 1 | jwt = $jwt; 58 | $this->tokens = $tokens; 59 | $this->server = $server; 60 | $this->clients = $clients; 61 | } 62 | 63 | /** 64 | * Create a new personal access token. 65 | * 66 | * @param mixed $userId 67 | * @param string $name 68 | * @param array $scopes 69 | * @return \Laravel\Passport\PersonalAccessTokenResult 70 | */ 71 | public function make($userId, $name, array $scopes = []) 72 | { 73 | $response = $this->dispatchRequestToAuthorizationServer( 74 | $this->createRequest($this->clients->personalAccessClient(), $userId, $scopes) 75 | ); 76 | 77 | $token = tap($this->findAccessToken($response), function ($token) use ($userId, $name) { 78 | $token->forceFill([ 79 | 'user_id' => $userId, 80 | 'name' => $name, 81 | ])->save(); 82 | }); 83 | 84 | return new PersonalAccessTokenResult( 85 | $response['access_token'], $token 86 | ); 87 | } 88 | 89 | /** 90 | * Create a request instance for the given client. 91 | * 92 | * @param \Laravel\Passport\Client $client 93 | * @param mixed $userId 94 | * @param array $scopes 95 | * @return \Zend\Diactoros\ServerRequest 96 | */ 97 | protected function createRequest($client, $userId, array $scopes) 98 | { 99 | return (new ServerRequest)->withParsedBody([ 100 | 'grant_type' => 'personal_access', 101 | 'client_id' => $client->id, 102 | 'client_secret' => $client->secret, 103 | 'user_id' => $userId, 104 | 'scope' => implode(' ', $scopes), 105 | ]); 106 | } 107 | 108 | /** 109 | * Dispatch the given request to the authorization server. 110 | * 111 | * @param \Zend\Diactoros\ServerRequest $request 112 | * @return array 113 | */ 114 | protected function dispatchRequestToAuthorizationServer(ServerRequest $request) 115 | { 116 | return json_decode($this->server->respondToAccessTokenRequest( 117 | $request, new Response 118 | )->getBody()->__toString(), true); 119 | } 120 | 121 | /** 122 | * Get the access token instance for the parsed response. 123 | * 124 | * @param array $response 125 | * @return Token 126 | */ 127 | protected function findAccessToken(array $response) 128 | { 129 | return $this->tokens->find( 130 | $this->jwt->parse($response['access_token'])->getClaim('jti') 131 | ); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Passport/RefreshToken.php: -------------------------------------------------------------------------------- 1 | 'bool', 37 | ]; 38 | 39 | /** 40 | * The attributes that should be mutated to dates. 41 | * 42 | * @var array 43 | */ 44 | protected $dates = [ 45 | 'expires_at', 46 | ]; 47 | 48 | /** 49 | * Indicates if the model should be timestamped. 50 | * 51 | * @var bool 52 | */ 53 | public $timestamps = false; 54 | 55 | /** 56 | * Get the access token that the refresh token belongs to. 57 | * 58 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 59 | */ 60 | public function accessToken() 61 | { 62 | return $this->belongsTo(Passport::tokenModel()); 63 | } 64 | 65 | /** 66 | * Revoke the token instance. 67 | * 68 | * @return bool 69 | */ 70 | public function revoke() 71 | { 72 | return $this->forceFill(['revoked' => true])->save(); 73 | } 74 | 75 | /** 76 | * Determine if the token is a transient JWT token. 77 | * 78 | * @return bool 79 | */ 80 | public function transient() 81 | { 82 | return false; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Passport/Token.php: -------------------------------------------------------------------------------- 1 | 'bool', 44 | ]; 45 | 46 | /** 47 | * The attributes that should be mutated to dates. 48 | * 49 | * @var array 50 | */ 51 | protected $dates = [ 52 | 'expires_at', 53 | ]; 54 | 55 | /** 56 | * Get the client that the token belongs to. 57 | * 58 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 59 | */ 60 | public function client() 61 | { 62 | return $this->belongsTo(Client::class); 63 | } 64 | 65 | /** 66 | * Get the user that the token belongs to. 67 | * 68 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 69 | */ 70 | public function user() 71 | { 72 | $provider = config('auth.guards.api.provider'); 73 | 74 | return $this->belongsTo(config('auth.providers.' . $provider . '.model')); 75 | } 76 | 77 | /** 78 | * Determine if the token has a given scope. 79 | * 80 | * @param string $scope 81 | * 82 | * @return bool 83 | */ 84 | public function can($scope) 85 | { 86 | return in_array('*', $this->scopes) || 87 | array_key_exists($scope, array_flip($this->scopes)); 88 | } 89 | 90 | /** 91 | * Determine if the token is missing a given scope. 92 | * 93 | * @param string $scope 94 | * @return bool 95 | */ 96 | public function cant($scope) 97 | { 98 | return !$this->can($scope); 99 | } 100 | 101 | /** 102 | * Revoke the token instance. 103 | * 104 | * @return void 105 | */ 106 | public function revoke() 107 | { 108 | $this->forceFill(['revoked' => true])->save(); 109 | } 110 | 111 | /** 112 | * Determine if the token is a transient JWT token. 113 | * 114 | * @return bool 115 | */ 116 | public function transient() 117 | { 118 | return false; 119 | } 120 | } 121 | --------------------------------------------------------------------------------