Laravel's 5.3 passport and api routes
Solution 1:
The problem with Laravel 5.3 passport is that unlike previous OAuth 2.0 Server for Laravel library offered by lucadegasperi, it has no API to make clients directly. So as if now the client can only be made through the front-end. FYI we wanted to use laravel passport solely for our mobile app so while creating and registering user we would have only EMAIL & Password and in some cases only Facebook UserID for facebook sign-in. So the following approach worked pretty well for our case and might differ for your scenario but may help you in the longer term to play around with laravel passport.
Note: Before following the below its assumed you have enabled Password Grant in your application.
So the way we solved it for our project on laravel 5.3 is as follows:
in the oauth_clients convert the id field into a normal field i.e. remove it as being primary key and make the data type as varchar so that we can store email address as client_ids as they are also unique for your system. Incase of Facebook login we store Facebook user IDs here in this column which again will be unique for each our client. Also for other tables like: oauth_access_tokens, oauth_auth_codes & oauth_personal_access_clients change client_id to VARCHAR(255) so that it can store email addresses or Facebook User IDs.
-
Now go to your models and create a model for oauth_clients table so that you can create client programmatically from the code while creating users.
<?php namespace App; use Illuminate\Database\Eloquent\Model; class OauthClient extends Model { protected $table = 'oauth_clients'; }
-
Then in your api.php route file add the following route:
Route::post('/register-user', function (Request $request) { $name = $request->input('name'); $email = $request->input('email'), $password = $request->input('password'), // save new user $user = \App\User::create([ 'name' => $name, 'email' => $email, 'password' => bcrypt($password), ]); // create oauth client $oauth_client = \App\OauthClient::create([ 'user_id' => $user->id, 'id' => $email, 'name' => $name, 'secret' => base64_encode(hash_hmac('sha256',$password, 'secret', true)), 'password_client' => 1, 'personal_access_client' => 0, 'redirect' => '', 'revoked' => 0, ]); return [ 'message' => 'user successfully created.' ]; });
In the above code snippet, you have to note that to generate the oauth_client secret you have to use some strong formula of encryption that you feel comfortable using it with your application. Also, use the same technique to generate the secret key on your mobile app for the respective client/user.
-
Now you can use the standard POST API offered by laravel passport to request access token through password grant using "oauth/token" using the following parameters:
grant_type : 'password' client_id : '<email with which the user is registered>' client_secret : '<generate the client secret from the mobile app>' username : '<email with which the user is registered>' password : '<password entered by the user>' scope : '<leave empty as default>'
-
The above will give you a response, if everything is correct, similar to :
{ "token_type": "Bearer", "expires_in": 3155673600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3In0.eyJhdWQiOiJzaHVqYWhtQGdtYWlsLmNvbSIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3IiwiaWF0IjoxNDc4MTQ1NjMyLCJuYmYiOjE0NzgxNDU2MzIsImV4cCI6NDYzMzgxOTIzMiwic3ViIjoiMSIsInNjb3BlcyI6W119.dj3g9b2AdPCK-im5uab-01SP71S7AR96R0FQTKKoaZV7M5ID1pSXDlmZw96o5Bd_Xsy0nUqFsPNRQsLvYaOuHZsP8v9mOVirBXLIBvPcBc6lDRdNXvRidNqeh4JHhJu9a5VzNlJPm3joBYSco4wYzNHs2BPSxXuuD3o63nKRHhuUHB-HwjVxj2GDwzEYXdZmf2ZXOGRJ99DlWGDvWx8xQgMQtd1E9Xk_Rs6Iu8tycjBpKBaC24AKxMI6T8DpelnFmUbMcz-pRsgCWCF_hxv6FpXav3jr1CLhhT58_udBvXjQAXEbtHeB7W_oaMcaqezHdAeOWDcnqREZHsnXHtKt0JpymcTWBkS2cg7sJzy6P9mOGgQ8B4gb8wt44_kHTeWnokk4yPFRZojkHLVZb8YL6hZxLlzgV1jCHUxXoHNe1VKlHArdlV8LAts9pqARZkyBRfwQ8oiTL-2m16FQ_qGg-9vI0Suv7d6_W126afI3LxqDBi8AyqpQzZX1FWmuJLV0QiNM0nzTyokzz7w1ilJP2PxIeUzMRlVaJyA395zq2HjbFEenCkd7bAmTGrgEkyWM6XEq1P7qIC_Ne_pLNAV6DLXUpg9bUWEHhHPXIDYKHS-c3N9fPDt8UVvGI8n0rPMieTN92NsYZ_6OqLNpcm6TrhMNZ9eg5EC0IPySrrv62jE", "refresh_token": "BbwRuDnVfm7tRQk7qSYByFbQKK+shYPDinYA9+q5c/ovIE1xETyWitvq6PU8AHnI5FWb06Nl2BVoBwCHCUmFaeRXQQgYY/i5vIDEQ/TJYFLVPRHDc7CKILF0kMakWKDk7wJdl5J6k5mN38th4pAAZOubiRoZ+2npLC7OSZd5Mq8LCBayzqtyy/QA5MY9ywCgb1PErzrGQhzB3mNhKj7U51ZnYT3nS5nCH7iJkCjaKvd/Hwsx2M6pXnpY45xlDVeTOjZxxaOF/e0+VT2FP2+TZMDRfrSMLBEkpbyX0M/VxunriRJPXTUvl3PW0sVOEa3J7+fbce0XWAKz7PNs3+hcdzD2Av2VHYF7/bJwcDCO77ky0G4JlHjqC0HnnGP2UWI5qR+tCSBga7+M1P3ESjcTCV6G6H+7f8SOSv9FECcJ8J5WUrU+EHrZ95bDtPc9scE4P3OEQaYchlC9GHk2ZoGo5oMJI6YACuRfbGQJNBjdjxvLIrAMrB6DNGDMbH6UZodkpZgQjGVuoCWgFEfLqegHbp34CjwL5ZFJGohV+E87KxedXE6aEseywyjmGLGZwAekjsjNwuxqD2QMb05sg9VkiUPMsvn45K9iCLS5clEKOTwkd+JuWw2IU80pA24aXN64RvOJX5VKMN6CPluJVLdjHeFL55SB7nlDjp15WhoMU1A=" }
Its only a temporary solution till laravel supports an external API for applications which only has a mobile as the only possible interface for creating oAuth clients and user.
Hope it helps you! Cheers.
Solution 2:
Because the marked answer was noted as correct I feel it necessary to note some key points that many I think would agree with:
You almost NEVER want put server process logic of that kind within your routes directory. Especially when working to create an API with the intent to put it into production. It's a dirty route to take and not entirely safe. UNLESS it's for things that are safe to process within your routes directory. Like, on a lesser scale, the base logic for sending a notification (SMS,email,push,slack) to staff members about a new letter/blog/memo being published as an example.
ALWAYS attempt to leverage and make use of as much of a framework's features as possible before attempting to "hackishly" accomplish a task that may have been accomplished multiple times before.
Ensure that you're doing the proper research about something that has been accomplished already. That way it makes it easier to simply reference a video or tutorial that shows how to properly do what someone is trying to do.
That being said, a good starting point would be to watch the following video that perfectly describes the basics of how to properly set up what you're looking to set up:
https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13
In many respects, the video tutorial is very well done and thorough from start to finish. Be sure to brush up on the different Grant_Types for OAuth2.0 as well so you'll have a better understanding as to what specific type you/your application need based on your application's position to consume the api:
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
In addition, be sure to USE laravel's out-of-the-box features for login and register when creating or logging in users. The Controllers are built for you when you perform the following in your console:
php artisan make:auth
Aside from that, if passport is some-what of a mystery, you can always pull in laravel/socialite package (https://github.com/laravel/socialite). It will allow you to "Log in with (Social Network Here)". Provided that is the route you're also aiming to go.
END NOTE: The piece I saw in your question that stuck out the most was how a person will register but will not login with facebook. Instead will have an access token to hit various API endpoints. So if I'm getting what you're saying right, you're aiming to use a user's data from facebook when data is returned, the user is considered logged in and is to be issued an access token. SO:
Use socialite to send a "login with facebook" request to facebook. This will get the user's data and leverage a bit of facebook's process of authentication.
When a request is returned with user data within the body run it through a check to ensure that there is data (a simply if statement should be fine). Since facebook will have already authenticated that user and the sent credentials you should be good to go.
-
You can either fire off an internal proxy within your Login Controller (which is the cleaner and safer way to do it) or you can issue a JWT (Which is covered in the last 5 minutes of the video posted in this answer above).
Below is some example code to get you started.
App\Http\Controllers\Auth\LoginController.php
class LoginController extends Controller { // ... protected function authenticateClient(Request $request) { $credentials = $this->credentials($request); $data = $request->all(); $user = User::where('email', $credentials['email'])->first(); $request->request->add([ 'grant_type' => $data['grant_type'], 'client_id' => $data['client_id'], 'client_secret' => $data['client_secret'], 'username' => $credentials['email'], 'password' => $credentials['password'], 'scope' => null, ]); $proxy = Request::create( 'oauth/token', 'POST' ); return Route::dispatch($proxy); } protected function authenticated(Request $request, $user) { return $this->authenticateClient($request); } protected function sendLoginResponse(Request $request) { $request->session()->regenerate(); $this->clearLoginAttempts($request); return $this->authenticated($request, $this->guard()->user()); } public function login(Request $request) { if ($this->guard('api')->attempt($credentials, $request->has('remember'))) { return $this->sendLoginResponse($request); } } }
The code above is used IN CASE you're aiming to use the Password Grant type for authenticating clients through passport. However, I would seriously look at the tutorial video before jumping the gun on anything. It WILL help you out a lot with how to use laravel 5.3 with passport.