How to use refresh token in codeigniter rest api? - php

I'm new in codeigniter 4 rest api and oath. I'm able to create login that return the token and the refresh token. My problem is when the token has expired. How can I get new token using the refresh token? Do I have to create a new function in the controller for that? Or can it be the same endpoint as the login? I've read in some articles that I need to send grant_type, client_id, client_secret and the refresh token as a post. But I don't know the endpoint on where to send this. I'm totally new to this, please help me. Thanks.
User.php(Controller)
<?php namespace App\Controllers;
use \App\Libraries\Oauth;
use \OAuth2\Request;
use CodeIgniter\API\ResponseTrait;
use App\Models\UserModel;
class User extends BaseController
{
use ResponseTrait;
public function login(){
$oauth = new Oauth();
$request = new Request();
$respond = $oauth->server->handleTokenRequest($request->createFromGlobals());
$code = $respond->getStatusCode();
$body = $respond->getResponseBody();
return $this->respond(json_decode($body), $code);
}
Oauth.php
<?php namespace App\Libraries;
//use \OAuth2\Storage\Pdo;
use \App\Libraries\CustomOauthStorage;
class Oauth{
var $server;
function __construct(){
$this->init();
}
public function init(){
$dsn = getenv('database.default.DSN');
$username = getenv('database.default.username');
$password = getenv('database.default.password');
$storage = new CustomOauthStorage(['dsn' => $dsn, 'username' => $username, 'password' => $password]);
$this->server = new \OAuth2\Server($storage);
$this->server->addGrantType(new \OAuth2\GrantType\UserCredentials($storage));
}
}

When you want to implement an OAuth2 system with CI4, you're free to making it however you want since nothing is already created to do so in the framework. Here it looks like you're using bshaffer oauth2 lib for PHP (try to read their cookbook. It personally helped me a lot implementing it in a CI4 project : https://bshaffer.github.io/oauth2-server-php-docs/cookbook).
First if you want to make a refresh token with this lib you have to add the refreshtoken grant type to your server.
$this->server->addGrantType(new \OAuth2\GrantType\UserCredentials($storage));
// this add the refresh token grant type.
// param 'always_issue_new_refresh_token' allows you to catch a new refresh token
// when making a call with a refresh token
$this->server->addGrantType(new \OAuth2\GrantType\RefreshToken($storage, [
'always_issue_new_refresh_token' => true
]));
Then the lib will handle it for you with $respond = $oauth->server->handleTokenRequest($request->createFromGlobals());. You don't need to add anything in your controller.
It's up to you to create a new route in your Config/Routes.php for the refresh token call. But as your controller code will be the exact same it could be a good point to keep it on the same route.
Also the HTTP request you will send to your oauth server must have :
Header Content-Type as application/x-www-form-urlencoded
A body parameter grant_type=refresh_token. That's how your lib will determine that it needs to use the refresh token process.
An other parameter named refresh_token with the actual refresh token
Don't forget to read the lib's documentation which is pretty small but really clean : https://bshaffer.github.io/oauth2-server-php-docs/grant-types/refresh-token/

Related

Laravel Http request to route sends forever

I want to have a link in an email that send to the user, the link is the url of the site and has an api token for the user to authenticate with.
however I am trying to send an api request to get the user details so I can authenticate the user and redirect them to the relavent page, however doing this I end up with a request the spins endlessly.
what could be the issue and if there are any other solutions please let me know.
the link/request looks like this
http://localhost:8005/api/token?_token=<API TOKEN>
The controller that handles the request
<?php
namespace App\Http\Controllers;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Http;
class PassportController extends Controller
{
function getToken(Request $request)
{
// return $request->_token;
return $user = Http::withToken($request->_token)->get('http://localhost:8005/api/user');
Auth::login($user);
return redirect('/dashboard');
}
}
Also when I send the request it gets stuck and I have to restart my php artisan serve again to make more requests, and every time i do so, It opens up on a new port, 8001,8002,8003 etc
You can make a call back to the app itself like this:
$tokenRequest = Request::create('/api/user', 'GET', ['name' => 'value']);
$tokenResult = app()->handle($tokenRequest);
Update the variables to match your implementations.

Laravel - Get returned data from an API within the Controller

I have an API /getuser which returns a reponse along with the user object:
$user = session()->get('current_user');
return response()->json(['user'=>$user]);
Now, I want to get the said returned api within my function public function show_user().
I tried $current_user = return redirect('/getuser'); but it's giving me an error - I don't know why specifically but I'm pretty sure you can't assign a returned response on a variable perhaps?
Reason why I'm using a different API on getting the user is because of Sessions. The api routes cannot read/store sessions properly (probably because they're stateless or something) so I placed that /getuser on the web routes which works perfectly. I could call the web "api" anywhere and it would give me the current user. Now however, I cannot reference the said current user within the api routes by doing session()->get()... since it wouldn't read sessions. My solution is to call that /getuser api I made on web routes and assign its returned response on a variable - which I have no idea how.
Is there anyway I could achieve something like that?
Thanks a ton!
You can use guzzle in laravel when you need to call api in your controller.
use GuzzleHttp\Client;
class MyController extends Controller {
public function show_user()
{
$client = new Client();
$res = $client->request('GET', '/getuser', [
'form_params' => [
'KEY' => 'VALUE',
]
]);
$result= $res->getBody();
dd($result);
}
Read blog here

How To Save PassportToken on user login laravel

i make API by laravel passport
i wanna save passport token in cookies when login is successful
i tried to make this in home controller but it always generate different key
Have you tried withCookie method of a Response object?
use Illuminate\Http\Response;
...
$UserToken = Auth::user()->createToken('MyApp')->accessToken;
$view = view('Ades Admin.DashBoard');
$response = new Response($view);
return $response->withCookie(cookie('valid', $UserToken, 10));

Laravel - Getting user details for method used in both web and api routes

I have a project in Laravel where I am using the same method for both a web and api route. So for example i would have the following:
//routes/web.php
Route::post("/import-results", "ImportController#doImport");
//routes/api.php
Route::post("/import-results/{auto}", "ImportController#doImport");
So regardless of the route the doImport() function will be called in the ImportContoller.
The import controller has a function like this (there is validation in the function but I have taken it out for simplicity):
public function doImport($auto = null){
$importData = new DataImport();
$importData->type = $_POST['type'];
$importData->data = $_POST['data'];
$importData->user = Auth::user()->name;
$importData->save();
$data = [
"success" => true,
"message" => "Message Here!"
]
if($auto){
return json_encode($data);
}else{
return view('import-message', $data);
}
}
As you can see this method uses Auth::user()->name; to identify which user imported the data. This is fine if i am logging in and using a regular web route but what about if i'm using an API and using basic auth where no sessions are created and I don't want sessions to persist if the api routes are called.
How do i get the user info when calling API routes?
Also for the web routes i have customised my login as i'm using ldap but essentially the login happens by doing $this->guard()->login($user, false); in a class with the AuthenticatesUsers trait.
I could do this for my API routes too but does this creates a session and how do i clear this session once the request has ended? Or is there a better way??
To make session work for both page submitting and api. You need work in web.php
Make both route in web.php
//Web.php
Route::post("/import-results", "ImportController#doImport");
Route::post("/api/import-results/{auto}", "ImportController#doImport");
api.php is stateless mean no session exist in api.php . It's working with token based like JWT.

Laravel Passport : Users only have one token not many

Laravel Passport has a very complex system for my app cause I think for this simple app it's very complex to have OAuth client's Id, Secret & ...
So I create a UserController myself to solve this complexity with these codes:
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\User;
use Response;
class UserController extends Controller
{
//
public function __construct(){
$this->content = array();
}
public function login(){
if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
$user = Auth::user();
$this->content['token'] = $user->createToken('URL APP')->accessToken;
$status = 200;
}
else{
$this->content['error'] = "Unauthorised";
$status = 401;
}
return response()->json($this->content, $status);
}
}
but problem is every time user sign in get new tokens & old tokens won't expire & User with old tokens can send valid request (Its should be invalid I think).
Is there any way to config passport to users has one token or I should do it myself?
Yes its a problem with jwt tokens. But you can overcome this problem by making your own methods or by using some other libraries. "jwt-auth" is also a library for token and this also got the blacklist method you can use to blacklist a token.
or you can make a middleware in your routes and cache the token in redis or memcached database and save it against user_id and match it everytime with requests.

Categories