Codeigniter RESTful web API for web and mobile applications - codeigniter

I'm having application with running good in codeigniter, mysql and jquery. Currently we are planning to evaluate our web application with mobile application. So we planned to develop web application, android, ios and blackberry. Everything is native application.
For everything we planned to develop codeigniter restful API (This is server for all the client web and mobiles).
For web application we planned to develop client with angular js. But every client access web api server only. My codeigniter controller now looks like API.
My question is,
1.Is this good idea to create single server for all the client both web and mobile
2.How to create unique authentication for both web and mobile apps
Because in web app we have the session but in mobile there is no session. So how to create authentication uniquely for both apps.
I have planned to send a token to client, once login get successful. And then after for each and every request to server, the client will send a token with the request header. I have no idea of how to do the same for mobile apps, as web app having session, and hence we can save the token into session variable in server. But in-case of mobile app, how to create server variable and maintain the tokens.
Please anyone help me to get clarify my doubts.

You can check out Codeigniter REST Controller
(https://github.com/chriskacerguis/codeigniter-restserver/tree/master/application). It has different methods POST, GET etc
For Authentication:
If a server get a login request, if the login parameters are valid allow the user to login, at the same time update the user db column with a session id (this is not php session id) - create a session with user id+time+some random string sha 1 or some other encryption. And valid this session with all other request.If session is not matching the services return invalid session message.
If a server get a login request from a user even if there is session exist, regenerate the session and update corresponding column in db, this will make previous session invalid.
And also, we can share a API KEY (known to developer of web and app) as http header parameter. If API key matches then only the request proceeds. The mentioned codeigniter controller has the option to set API key.
Hope it is clear..

<?php
class Api_ci extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('Api_model');
$this->load->helper('text');
}
// code for login *api*-------------------------------
public function login_api_ci(){
$email = $this->input->get('email');
$pass = $this->input->get('password');
$query = $this->Api_model->login_api($email,$pass);
echo json_encode($query);
}
}
?>
<?php
class Api_model extends CI_Model{
public function __construct()
{
parent::__construct();
// Your own constructor code
$this->load->database();
}
// code for login api
public function login_api($username,$password){
$query = $this->db->query("SELECT * FROM `host_users` WHERE `email` = '$username' AND `password` = '$password'");
return $query->result_array();
}
}
?>
After these process, your API URL your domain name and / class name, class function:
www.example.com/Api_ci/login_api_ci?email=gaurav#gmail.com&password=1234567899
Output like this :
[{"id":"112","f_name":"gaurav","l_name":"singh","email":"gaurav#gmail.com","mob":"1234567899","password":"1234567899","img":null}]

Just to update this thread, I feel like creating a RESTFUL web API using Codeigniter is overkill, there's a lot of things that are unnecessary unless you are building a monolith system.
I prefer just creating a simple API without framework is better and lighter, it can also easily be scaled because nowadays microservices has more benefits than a monolith type of development.

Related

Laravel 8 API email verification flow using Sanctum

I'm currently making an API for a mobile app but I think I'm a bit confused with how email verification and authentication is meant to work. I'm attempting to implement the following flow:
User registers in the mobile app and it sends a request to the API
Laravel creates the user and fires off an email
User receives the email and clicks on the link
Laravel verifies the user and redirects them to the mobile app via deep-link
However when the user clicks the email link a "route login not defined" error is rendered.
Which makes sense, because the user is not authenticated at the time. But am I getting this wrong?
Should I authenticate the user prior to sending the email? And will that work, given that we're using Sanctum rather than "regular" authentication?
Currently this is what I'm doing:
// web.php
Route::get('/email/verify/{id}/{hash}', [EmailVerificationController::class, 'verify'])
->middleware('signed') //note that I don't use the auth or auth:sanctum middlewares
->name('verification.verify');
// EmailVerificationController.php
public function verify(Request $request)
{
$user = User::findOrFail($request->id);
if ($user->email_verified_at) {
return '';
}
if ($user->markEmailAsVerified()) {
event(new Verified($user));
}
return redirect()->away('app://open'); // The deep link
}
Is there any security risk here? Should I at any point authenticate the user before or after they click the link?
I wanted to avoid rendering "web views" as much as possible.
I think that the best way is to implement two different paths based on the source of the user.
Regular email validation for users coming from a browser
The user will just follow the link delivered by email, you can do that with or without authentication (maybe with transparent cookie authentication). If the validation is fulfilled redirect them back to the home page.
Mobile users coming from the mobile application
I would send a PIN (with some kind of expire mechanism) via email and ask them to put it inside the APP to verify the account. This can even be protected with auth middleware using the JWT token with the verification API call.
I don't see any security issue with this last one.

Add multiple authentication mechanism for different api groups springboot

We have an existing spring-boot application that supports basic Authentication with spring-security. this application uses spring templating so it accepts form data as input and saves sessions by doing authentication.
the login page is at /login after successful login it redirects to the home page of the website.
in the same spring boot service, we want to start supporting JSON based API which would be used by the Mobile app.
we were thinking of adding login API at /api/login which will be served for mobile devices.
is there a way where we can say
for /login use default authentication class and for /api/login use some other custom class which will read JSON data and will do Authentication.
we also want to use different page for unAuthorized access. as existing one renders custom HTML page. but with API we want to send JSON response with HTTP code.
Not a Java person, but generally speaking this can be done by creating a different controller that would handle the /api/login route.
Here's snippet below that might help :
[Source : https://spring.io/guides/gs/spring-boot/]
package com.example.springboot;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
#RestController
public class HelloController {
#RequestMapping("/api/login")
public String LoginAPI() {
// handle your authentication logic here.
}
}
I would strongly recommend against using the session based authentication. It's simply not designed for modern applications. If the option is open, you can take a upgrade to token based authentication (jwt.io), that would make your life much much easier.
If you must implement the session based authentication for mobile app as well. here's what you need to do
create the session on server
set the session key as a part of cookies in the response header
store the cookies in your app.
Include the cookies in request header in subsequent API calls from mobile app.
Again, not a Java person. Just hoping to help.

Laravel - read database credentials from a remote api

There is a central web app 'AppsManager' that stores users and database credentials for all other web apps. This has an api to validate the login in other web apps and also serves database credentials.
So in a different laravel app -that has it's own database- I am asked to implement a different way of using database credentials.
The request is forLaravel to read it's database credentials from the 'AppsManager' api instead of the default .env file.
Is this a good practice ? How can be done in Laravel ?
I am not sure if this is a good practice or not, personnally I dont think it is a good idea to have credentials sent between apps.
Nonetheless, what I would do, in your situation, is create a new configuration in config/database.php to explicitly tell Laravel what connection it should use to have this distant database.
Inside the models that use this database you can specify :
<?php
class MyModel extends Model {
protected $connection = 'name-of-the-connection-you-gave-in-the-config-file';
}
Or if you use the DB facade, you can just call DB::connection('name-of-the-connection-you-gave-in-the-config-file') as explained here in the docs.

Mysterious users in my database that didn't come from my registration process

I have a Laravel-5.5 application in development with a live test application exposed on Google App Engine. My registration process includes the standard Auth registration from Laravel. The RegisterController then redirects to a profile page if there isn't one for the user already.
public function redirectTo()
{
if (!Auth::user()->profile)
{
return '/profile';
}
else
{
return $this->redirectTo;
}
}
The profile controller creates a new userprofile record for the user automatically as the page loads.
$(document).ready(function ()
{
...
getProfileData(profileId);
...
});
getProfileData() posts to the controller. If ProfileId is empty, the controller creates a new record and sends a verification email to the registered address.
How can a user be created without then being redirected and a profile being created?
Users are being created on the live site without profiles or sent verification emails. The user_agent in the session records for these users appear to be real.
Any ideas about how these users are being created and how to stop it would be most helpful.
I believe that Laravel is actively being attacked by actors that are seeking sites with poor security practices. It starts with visiting the site and getting an active session, Then harvesting the sessions csrf-token and using the token in a non site generated post (crawler?) to the standard Laravel registration route.
Since my site has a two part registration that generates a profile and the profile needs to be verified by a human before access is granted, registering and then ignoring the response's redirect to the profile page gets the partially completed registration.
To stop the resulting database clutter in the users table I changed both the standard authentication routes and the expected fields that are returned from the registration form.
Since these changes I have had no half registered users show up in the database. I'll update this answer if I ever see more of this activity.

User registration for API/SPA

I am creating an API and a separate front-end app that will consume said API. In my particular case I'm using Laravel Passport for my API and some VueJS for my frontend app.
In order for a user to create an account, a user must POST to a route (/oauth/token) on the API which, requires a client_secret to be passed (https://laravel.com/docs/5.3/passport#password-grant-tokens).
The only options I see are:
Having the client_secret sent as a header from my frontend app. However, putting this token out in the open doesn't seem smart.
Don't require the client_secret at all. This doesn't seem much better than option 1.
Have a dynamic page on my frontend app that can securely store the client_secret and then send it to the API. While this is obviously the most secure, it seems to partially defeat the purpose of a fully static frontend (SPA).
What's the best practice for this type of approach? I've searched for how this is dealt with in general with an API and SPA, but I haven't found anything that points me in the right direction.
From my point of view, the Laravel Passport component seems to implement the OAuth2 Framework Protocol incorrectly.
The client_id and client_secret parameters are not part of the grant type.
For the Resource Owner Password Credentials grant type, the required parameters are username and password (see RFC6749 section 4.3.2).
client_id and client_secret are used to authenticate a confidential client that sends its credentials through the body parameters (see RFC6749 section 2.3.1). The Laravel Passport component should allow other client authentication schemes (especially the HTTP Basic Authentication Scheme). The RFC6749 also indicates that
Including the client credentials in the request-body using the two
parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
to directly utilize the HTTP Basic authentication scheme
The OpenID Connect Core specification lists some of those schemes in its section 9. The RFC6749 does not indicates how public clients (e.g. SPA) should authenticate against the token endpoint. They are supposed to use the Implicit grant type which does not require a client authentication.
Anyway, a solution could be to use a kind of proxy. This proxy has to be installed on a server. It will receive all requests from the SPA (without client secret), add the client secret and transmit the modified request to the Laravel Passport endpoint. Then the response is sent to the SPA. This way the SPA never exposes the client secret.
I came across the same problem, and I didn't find much more documentation on the problem.
So here is what I did, that seems working great so far, you'll tell me if you see anything wrong.
For my apps, I'll be using password grant clients that I create on the fly for each "client" of my app. By client I mean browser, or mobile app, or anything.
Each browser, checks at startup if they have any client_id and client_secret into localStorage (or cookies, or anything). Then, if they don't, they call an endpoint of your API that will create a password grant client and return the information to the browser.
The browser will then be able to login the user using this new client information and his credentials.
Here is the controller I use to create a password grant client:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Http\Request;
use Laravel\Passport\ClientRepository;
class AuthController extends Controller
{
protected $hasher;
protected $clients;
public function __construct (Hasher $hasher, ClientRepository $clients)
{
$this->hasher = $hasher;
$this->clients = $clients;
}
public function makeClient (Request $request)
{
$client = $this->clients->create(null,$request->header('User-Agent','Unknown Device'), '', false, true);
return $client->makeVisible('secret');
}
}
As you can see, as the name for the client, I try to store the User-Agent of the browser. So I can potentially display a page to my user with all his clients and giving him the right to revoke some clients like:
"Google Chrome, New York". You can also store the client IP or anything in there that will help you identify more precisely the client type of device...
The simpler way would be to take care of the user registration with the Laravel app running Passport itself (and not with the frontend Vuejs app via API).
Once the user is registered and logged in, you can use Passport's CreateFreshApiToken middleware to add a token to the user's cookie while loading up your frontend app. No more problem with client_secret.
See https://laravel.com/docs/5.3/passport#consuming-your-api-with-javascript and https://mattstauffer.co/blog/introducing-laravel-passport#super-powered-access-to-the-api-for-frontend-views
Also oauth/token doesn't create a user I believe? It is supposed to deliver a token (for password grant client) or an authorization code (authorization code grant client).

Resources