How to identify the tenant in a multi-tenant application using React? - php

I'm building a multi-tenant application with a React.js frontend and Laravel API. When the user logs in, I add the tenant_id to their session. When a request is made from the frontend, I plan to use a middleware that gets the tenant_id from the user's session, and attach it to the request query as a url param (e.g. api.com?tenant_id=xxx), then call next() to continue with the request.
Directly after, I'll call the InitializeTenancyByRequestData middleware from the tenancy-for-laravel package, that will scope the user to the correct tenant database schema based on the tenant_id attached to the url in the previous middleware.
Is storing the tenant_id in session data secure? And is this overall approach a reasonable way to go about multi-tenancy using multiple schemas with a SPA frontend and API?

Related

Laravel Authentication API Sanctum – With Custom Database

First important information: I’m new to Laravel, so your patience is appreciated.
I’m currently migrating a framework of mine to Laravel and still in the early stages. I know that Laravel has it’s own database construction mechanism that is recommended to use the migrations and the Models, however, for my purpose, I’d like to use my own database that I use in other systems that I’ve built in the past. The idea for this system is to have a shared database, but operable through different tech stacks.
This is my current scenario:
Laravel 8
Sanctum 2.14
Frontend (Laravel):
I’ve built a very simple login page that has a controller and sends data (user and password) to my backend (Laravel). In the backend (different server), I grab the data and check if the data is correct. Being correct, I send a json response with some data, like:
returnStatus = true
loginVerification = true
IDCrypt = asdfasd4fa654sd54a (encrypted ID to grab in the frontend again)
Up till here, it’s working fine, as I wanted and very similar to my legacy systems.
My idea would be to get this response in the frontend, via auth token managed by Sanctum and use a middleware to check the token in order to let the user access some web routes.
I’ve watched some videos, but I’m only finding videos that use all the database mechanism that Laravel provides.
However, my intention would be to generate the token with data from my own table and data objects I created (without any existing Laravel´s models).
Is there a way for me to do this?
How would I set the token in the backend and include in my response?
How would I grab the token in the frontend in a secure way?
Lets say you have a model LegacyUser and this is your existing authenticable entity.
In this model simply override methods defined in the Laravel\Sanctum\HasApiTokens trait. Specifically createToken and the tokens relation for your use case by the sounds.
Then you can create tokens anywhere like usual with
$user = LegacyUser::find( $id );
$token = $user->createToken('token-name');
Then us the token as usual.
NOTE: if you're also changing how the tokens are stored/retrieved you'll need to set the token model, docs cover that here: https://laravel.com/docs/8.x/sanctum#overriding-default-models
If you want to avoid using authenticable entites (ie, no laravel models) entirely that's going to be more complicated and Passport might be a better shout, as client_credentials dont need to be associated to a user entity.
Alternatively: Write your own middleware that is compatbile with your existing auth process.

What would be a proper way to handle tokens in monolith application?

I have a monolith web application powered by Laravel. Users access different forms and some of them have button on them that executes Ajax call to the back-end (example relative endpoint: api/external/get-current-temperature). A back-end function that handles the request than connects to an external service via API and obtain data, writes some log in database and pass data back to requestor (front-end user). But in order to execute any API call it has to authenticate and obtain a Token.
Question:
I have multiple users that can potentially request api/external/get-current-temperature at the same time. How should I handle authorization/token? Should I store it in database and check its expiration time before requesting a new one or what? How would I refresh it? - The external provide has no specific function that could be utilized to verify token. But I know for sure the token is valid 60 minutes.
The users of your application never have to be mixed up / mistaken with your foreign API. You can and should provide you own mechanism (i.e. tokens) to authenticate any users. If users are authenticated the external API is used, else an error-message could be provided by your application.
As users also fill several different form it's quite possible that you save some user-data. If every user has own authentication credentials it's easy and much more secure to provide only the user's own data. If you use for every user the same authentication token in your own application you might get the situation that one user can see data from another user.
So see it like this:
You / your application is the user of the external API, therefore you need only one authenticqation token for it. Your application users use the external API as a service and as that you should provide it in your app. The data though that are provided to the service might differ from user to user.
Example payment application:
The API is always the same, you as developer get an API key, but the payments are for every user of your application differently. As developer you might never even able to see, store or track the user-data that are exchanged between the foreign service and the user, but your app serves as hub and provides perhaps also some products or services that are considered in any payments.

CreateFreshAPIToken or Personal Access Token. And does CreateFreshAPIToken work with AJAX?

I am making a API based web application. It will contain various users like normal users, admins with webpages with tables for updating, deleting, showing stuff. There will be obviously many pages and access will depend on scope of user. I am confused and stuck at point that:
Should I generate personal access token with a scope every-time a user logins and use that for checking user's group(if it has permission or not) for giving access to webpages and for making some requests.
OR
Should I use CreateFreshApiToken Middleware for requests and I should just check user's group while logging in to give him access to some webpages.
I hope you understood what I'm trying to say.
And CreateFreshApiToken middleware attaches a laravel_token cookie to outgoing responses. If I'm using AJAX, does that work? If not, does that mean I will always have to pass access token with request?
I would go for the second scenario and use the CreateFreshApiToken Middleware, because scopes are in a certain sense subordinate to the user groups / user rights / user roles in your application.
For example, a user can have the rights to place and view orders once logged in to your application. But, developers of for example a mobile app consuming your API, could decide to only give users logging in to this app rights to view orders, i.e. the orders.view scope and not the rights to place orders. Compare this to for example a Google API. As a user of Gmail, you have the rights to read and delete emails, etc. But when you develop an app consuming the Gmail API, you could decide that the app only needs and only will ask the user for the scopes that are needed to read emails.
Managing the whole authorization layer in a Laravel application with scopes is therefore very thin. In most cases it is better to separate the authorization layer of your applications (user roles, rights etc.) with the authorization layer of your API (scopes).
The CreateFreshApiToken middleware is meant for consuming your API with JavaScript and AJAX. The laravel_token will be attached as a cookie to each AJAX request after the first GET request that is made to a web route after logging in (a request to /home is made automatically by the Laravel Auth scaffolding after login). Description can be found in this part of the Passport documentation: https://laravel.com/docs/5.4/passport#consuming-your-api-with-javascript
Personal Access Tokens can be seen as API keys. API consumers can use this key to authorise with your API, without going through the OAuth2 flow. You would have to create a proxy from your JavaScript application to your API to make requests with this token, which would be very strange.

best approach for multi tenant SaaS application

I'm trying to build a Multi tenant SaaS application, and i know there are multiple approaches to that, but i picked the multi-database one i think it would fit most.
so I create a db for each tenant and store a table of tenants in the main db
and connect users to their respective db based on the subdomain.
now my issue here is where to store the users, in the main db? or the tenant db, storing the users in the main db is going to make it difficult to get user related models in other db's, but storing it inside tenants db would make it difficult to authenticate on all users ...
also what's the best scenario?
authenticate, get jwt token.
send token with each request.
on each request validate token, check subdomain, connect to respective tenant db, execute request.
is this a good approach? what should I do with the users table issue?
ThnQ
I can offer third option. Have user both in tenant and main db. You can then create procedure to update main db when user changes in tenant db (or vice versa).
Also, I don't know models in Laravel, but MySQL doesn't have problem with cross database JOINs.
Good option will be to keep users in tenant database. As you are distinguishing your tenant based on sub-domain, you can tell your authentication system to query sub-domain specific database.
Sharing flow of authentication
User hits the sub-domain to login for application
User credentials will be sent to application
Before passing credentials to authentication, decide database for user authentication based on sub-domain from which user came.
Pass database name, user credentials to authentication system
Authentication system query specific database and authenticate user
Generate session

How to manage sessions with Laravel 5.0 as backend

I am developing a web application in Laravel. Now I'm in the process of creating an android app. I need to create a web service (back end) in Laravel, but I don't know how to manage the sessions (auth) in the request.
My idea is to create a unique token for every session, and store it in a database. So, every request need the token be included, and my backend will check if the token is valid or not.
How can I modify the login functionality that comes with Laravel 5.0 to create an return the token?
I read the documentation and some articles in the internet, but it is still not clear to me.
You can create a token during registration of the app which should correspond with the user id. This token will be used together with the user id anytime you call any of your api's to authenticate the user.
You can create a filter named custom_authentication and check for the token validity inside that filter. Now just apply this filter before every routes, which you want to be authenticated.
Using only simple authentication token is not very secure, you need to go with HTTPS always.
If you want to make the API secure with HTTP, you might have to implement OAuth with the help of packages like this.

Categories