Embed the SaaSus SDK into your web application and make it multi-tenant

Embed the SaaSus SDK in your web application

*Programming knowledge is required

Reconfirm SaaS ID, API Key and Client Secret

First, let's display the API key in the SaaSus development console. Use this in your application settings
(Be careful not to leak your API key to anyone else. The API key displayed in this tutorial has already been deactivated.)

1295

Preparing to use the SaaSus SDK

Now, let's open the sample application we prepared earlier in the development environment.

As we did at the beginning, make sure that the docker container is started using init.sh and the sample application is running on http://localhost/board. Put it down please.

First, to easily use the SaaSus Platform, embed the SaaSus SDK into your application.

This time it's PHP, so I'll use composer.

Enter the php container and setup using composer.

repo$ docker compose exec php bash
[email protected]:/var/www# cd api
[email protected]:/var/www/api# composer config repositories.saasus-platform/saasus-sdk-php vcs https://github.com/saasus-platform/saasus-sdk-php

In the api directory add it using the composer command

[email protected]:/var/www/api# composer require saasus-platform/saasus-sdk-php:1.0.0

After installing the SaaSus SDK, let's first define the environment variables necessary for using the SaaSus SDK.

Create a .env file by copying the .env.example file in the api directory and edit the following part at the bottom of that .env file

### for SaaS Platform
SAASUS_SAAS_ID="saasid_98tjo3wifaoua (SaaS ID of the screen)"
SAASUS_API_KEY="apikey_kjntowjfoasnkjntwonsflajsno4as (Screen API KEY)"
SAASUS_SECRET_KEY=" (screen client secret)"
SAASUS_LOGIN_URL="https://auth.sample.saasus.jp/ (Login screen URL)"

SAASUS_SAAS_ID, SAASUS_API_KEY, SAASUS_SECRET_KEY are the SaaS ID, API Key, and client secret displayed on the screen earlier,
SAASUS_LOGIN_URL sets the URL of the login screen created in the SaaSus development console.

Include authentication module

Next, include the SaaSus Platform's authentication module.

In our application, we require authentication at the root of all URIs. If it is not authenticated, the application cannot be used. Therefore, we will incorporate SaaSus authentication function as Middleware of Laravel.

The current situation is

api/routes/web.php

, the Laravel standard authentication function is used, so replace it with the SaaSus authentication function.

this part

Route::middleware('auth')->group(function () {
    Route::get('/', function () {
        return view('welcome');
    });
    Route::get('/dispatch', 'App\Http\Controllers\[email protected]')->name('dispatch');
    Route::get('/board', 'App\Http\Controllers\[email protected]')->name('board');
    Route::post('/post', 'App\Http\Controllers\[email protected]')->name('post');
});

require __DIR__ . '/auth.php';

of

// Route::middleware('auth')->group(function () {
// Route::get('/', function () {
// return view('welcome');
// });
// Use SaaSus SDK standard Auth Middleware
Route::middleware(\AntiPatternInc\Saasus\Laravel\Middleware\Auth::class)->group(function () {
    Route::get('/dispatch', 'App\Http\Controllers\[email protected]')->name('dispatch');
    Route::get('/board', 'App\Http\Controllers\[email protected]')->name('board');
    Route::post('/post', 'App\Http\Controllers\[email protected]')->name('post');

    Route::redirect('/', '/board');
});

// require __DIR__ . '/auth.php';

Do it like this.

And prepare a receiver for callback from the authentication screen. Earlier, we defined the callback destination as http://localhost/callback in the SaaSus development console, so we can receive it at /callback .

Similarly, add the following to the last line of api/routes/web.php:

// Use the SaaS SDK standard Callback Controller to store JWT in Cookie or Local Storage
Route::get('/callback', 'AntiPatternInc\Saasus\Laravel\Controllers\[email protected]');

In addition, add the path to api/config/view.php so that you can use the views provided by the SaaSus SDK

    'paths' => [
        resource_path('views'),
        # ↓Add this line: View directory provided by SaaSus SDK
        resource_path('../vendor/saasus-platform/saasus-sdk-php/src/Laravel/Views'),
    ],

With this setup, the authentication information set in the SaaSus Platform will be passed as part of the request when the controller of the application is reached.

Add a Request argument to the index of api/app/Http/Controllers/MessageController.php and use dd to check if $request contains userinfo

Please change the following 4 lines.

    public function index(Request $request)
    {
        // Check if user information is passed from SaaSus Platform
        dd($request->userinfo);

So far, the basics of cooperation have been established.

Now, let's actually log in from the SaaSus Platform and check the operation.

Confirmation of SaaSus SDK integration

Display the login screen created in the SaaSus Platform.

Please display the login screen of the domain you set yourself, such as https://auth.sample.saasus.jp.

644

When you log in with the email address and password of the user you created earlier, you will be redirected to the URL set in the Callback URL along with your authentication information.

For example, let's log in with [email protected]

If the previous code actually works, it should look like this after login.

1296

On the application side, you can see that the user information and tenant information set in the SaaSus Platform earlier can be obtained.

The URL to redirect to is received by her Callback processing of the SaaS SDK standard this time (http://localhost/callback), and in that process he stores authentication information in the browser's local storage and cookies to remember.

Then, with the Auth Middleware of the SaaSus SDK, use the SaaSus Platform to validate the authentication information, get the user information, and fill it in the Request object.

After that, the application's controller will take over, so at this point the application already has the logged-in person's information.

Now let's use this information to make our bulletin board application multi-tenant ready!

Making the sample application multi-tenant

Since api/app/Http/Controllers/MessageController.php is the main processing, let's put the processing for multi-tenant support here.

First, change the display part.
Let's rewrite the whole public function index part.

    public function index(Request $request)
    {
        // $request->userinfo contains various user information and tenant information, so use it
        $messages = Message::where('tenant_id', $request->userinfo['tenants'][0]['id'])->get();
        return view('messageBoard.index', ['messages' => $messages, 'plans' => $this::PLANS, 'tenant_name' => $request->userinfo['tenants'][0]['name ']]);
    }

In this way, we will search the DB based on the passed tenant ID.

Below is the post part.

    public function post(Request $request)
    {
        $validated = $request->validate([
            'message' => 'required|max:255'
        ]);

        // Acquire various information from userinfo of $request and use it for judgment
        $message = Message::create([
             'tenant_id' => $request->userinfo['tenants'][0]['id'],
             'user_id' => $request->userinfo['tenants'][0]['user_attribute']['username'],
             'message' => $request->message,
         ]);

        $request->session()->regenerateToken();
        return redirect()->route('board');
    }

Store tenant ID and user name as a set based on the passed user attributes.

I will try to display the user ID on the screen display as well.

Edit api/resources/views/messageBoard/index.blade.php.

Change this $message->user->name part to $message->user_id around line 32.

Before correction:

                    <div class="mt-4">
                        <p>
                            {{ $message->user->name }}
                            <span class="text-xs text-gray-500">
                                {{ $message->created_at->format('Y/m/d H:i') }}
                            </span>
                        </p>

Revised:

                    <div class="mt-4">
                        <p>
                            {{ $message->user_id }}
                            <span class="text-xs text-gray-500">
                                {{ $message->created_at->format('Y/m/d H:i') }}
                            </span>
                        </p>

Multi-tenant support is now available!

Now let's log in and try it out.

As before, log in from the login screen created in SaaSus Platform.

When you log in, you can see that the tenant name has changed to what you set in the SaaS development console earlier.

1518

We don't have any data yet, so let's post some.

2086

It was confirmed that the user name was also displayed.

So let's go back to the login screen again, log in as [email protected], and make some posts.

2472

Of course it will be reflected on the screen.

Now let's log in with another tenant's user, [email protected]

2264

The display of the tenant name has changed, and you can confirm that the content is empty.

I was able to confirm that I can only access the information of my own tenant.

Now, after posting several posts in the same way, log in with [email protected] and confirm that the information of the same tenant can be displayed.

2400

Thus, per-tenant isolation is complete.

As for the separation method this time, we used a pool model to separate tenants within the same DB and separated tenants using a simple method. Even if you select a tenant separation method according to your requirements, such as schema separation or database separation, you can also use the SaaSus SDK to acquire tenant information and implement it.

Now that we have separated tenants, let's implement billing-related functions.

Let's implement the first steps of pricing, metering, and billing. For billing, we use a billing SaaS called Stripe. If you don't use Stripe, skip the billing part.


What’s Next