So, done some research about the issue and now have some results. The authentication process now looks like this:
On the CLIENT:
- Use the Facebook API to login and get an OAUTH2 code.
- Exchange this code for an access token.
- Request an access token from my API, including the Facebook token as
a parameter
On the API
Receive access token request.
Make a request to the /me Facebook graph using the facebook access
token
Verify that the Facebook user exists and match to a user in my
database
Create my own access token, save it and return it to the client to be
used from this point forward
First of all I created a migration for user table:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id')->unique();
$table->bigInteger('facebook_id')->unique();
$table->string('name')->unique();
$table->string('email')->unique();
$table->string('password')->nullable();
$table->string('accessToken')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
Then I added LaravelFacebookSdk to the project which is fully unit-tested package for easily integrating the Facebook SDK v5 into Laravel and Lumen.
Then I added some routs for authentication:
Route::group(['prefix' => '/auth' /*, 'middleware' => 'throttle:10,5'*/], function () {
Route::get('/', 'ApiAuthController@index');
Route::get('/base', 'ApiAuthController@baseAuth');
Route::get('/fb', 'ApiAuthController@facebookAuth');
Route::get('/vk', 'ApiAuthController@vkAuth');
});
And created a controller to handle these routes:
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use SammyK\LaravelFacebookSdk\LaravelFacebookSdk;
use App\User;
class ApiAuthController extends Controller
{
protected $baseAuthFailedResponse = [
'status' => false,
'message' => 'Base authentication failed'
];
protected $facebookAuthFailedResponse = [
'status' => false,
'message' => 'Facebook authentication failed'
];
protected $vkAuthFailedResponse = [
'status' => false,
'message' => 'VK authentication failed'
];
/**
* Echo function
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request){
return response()->json($request);
}
/**
* Authorise user with base authorisation using email and password
*
* @param Request $request - expects fields: email, password
* @return \Illuminate\Http\JsonResponse
*/
public function baseAuth(Request $request){
$isAuthorised = Auth::attempt(
array(
'email' => $request->input('email'),
'password' => $request->input('password')
)
);
if ($isAuthorised){
return response()->json(Auth::user());
}
return response()->json($this->baseAuthFailedResponse);
}
/**
* Authorise user using facebook accessToken received in the request
*
* @param Request $request - expects fields: accessToken, username, fullName, email
* @return \Illuminate\Http\JsonResponse
*/
public function facebookAuth(Request $request, LaravelFacebookSdk $fb){
if(!Auth::check()){
// Receive access token request.
$accessToken = $request->input('accessToken');
// Make a request to the /me Facebook graph using the facebook access token
try {
$response = $fb->get('/me?fields=id,name,email', $accessToken);
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
$this->facebookAuthFailedResponse['details']['message'] = $e->getMessage();
$this->facebookAuthFailedResponse['details']['error_code'] = $e->getCode();
return response()->json($this->facebookAuthFailedResponse);
}
// Verify that the Facebook user exists and match to a user in my database or create new one
// Convert the response to a `Facebook/GraphNodes/GraphUser` collection
$facebookUser = $response->getGraphUser();
// Create the user if it does not exist or update the existing entry.
// This will only work if you've added the SyncableGraphNodeTrait to your User model.
$user = User::createOrUpdateGraphNode($facebookUser);
Auth::login($user, true);
}
return response()->json(Auth::user());
}
public function vkAuth(Request $request){
return response()->json($this->vkAuthFailedResponse);
}
}
Also, as you can see I used a function $user = User::createOrUpdateGraphNode($facebookUser); which provided by LaravelFacebookSdk. To use it in our model we should implement the SyncableGraphNodeTrait. This method really makes it easy to take data that was returned directly from Facebook and create or update it in the local database.
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;
class User extends Authenticatable
{
use SyncableGraphNodeTrait;
/**
* The keys of the array are the names of the fields on the Graph node.
* The values of the array are the names of the columns in the local database.
*/
protected static $graph_node_field_aliases = [
'id' => 'facebook_id'
];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
If someone have any notes about solution, please provide it in comments.
UPD: The auth process description I'm got from this topic. And also this topic was very useful. An API description from the official site. How to easy remember the user I found in this topc. And there I found some useful information about API servers on Laravel. And good description about authentication with tokens