Connect Your Own Login System

Overview

If your website or app already has its own sign-up and login, for example a SaaS product built with Laravel, Rails or Node.js, you keep it. UniSignIn connects to it so every user has one profile with their account details, their data from your system and what they do in your app.

There are three parts:

  1. Log users in: when a user logs into your app, log them into UniSignIn with an SSO token. UniSignIn creates the user on first login and links their earlier anonymous visits to the profile.
  2. Push profile data: send data from your servers, such as plan, role, company or signup date, to UniSignIn profiles.
  3. Track activity: send events and tags from your pages for the actions that matter, such as creating a project or inviting a teammate.

You can then use all of it in Segments, Orchestration, Experiences and Data Exchange exports.

Before you start

  1. Install the UniSignIn tag on the pages of your app, including the pages behind login.
  2. Create an SSO Key Pair in Connect → SSO Token. You get an SSO_PUBLIC_KEY and an SSO_PRIVATE_KEY.
  3. Create an API key in Connect → API Keys and copy its Secret Key, see API Keys.

Keep the SSO private key and the API Secret Key on your server only. Never put them in page code or an app.

Step 1: Log users into UniSignIn

Create the SSO token on your server

The token is your user's details signed with your SSO private key, see SSO for the format. In PHP:

function unisigninSSOToken(string $email, string $firstName, string $lastName, string $registeredAt): string
{
    return base64_encode(json_encode([
        'email' => $email,
        'first_name' => $firstName,
        'last_name' => $lastName,
        'full_name' => trim($firstName . ' ' . $lastName),
        'reg_date' => $registeredAt,
        'public_key' => getenv('UNISIGNIN_SSO_PUBLIC_KEY'),
        'signature' => hash('sha512', $email . '-' . getenv('UNISIGNIN_SSO_PRIVATE_KEY')),
    ]));
}

Log in on the page

On pages where your user is logged in, check whether they are also logged into UniSignIn, and log them in if not:

window.unisignin = window.unisignin || {}
window.unisignin.cmd = window.unisignin.cmd || []

window.unisignin.cmd.push([
  'getUser',
  function (user) {
    if (!user.isLogin) {
      window.unisignin.cmd.push(['sso_login', 'SSO_TOKEN', function (result) {}])
    }
  },
])

Replace SSO_TOKEN with the token from your server.

The first time a user logs in, UniSignIn creates their account with the email in the token. Users are matched by email, so use the same email as in your system. Add reg_date, the date the user registered in your system, so their UniSignIn registration date matches your records. Use an ISO 8601 date with a time zone, e.g. 2024-05-01T09:30:00Z, or a Unix timestamp.

Log out

When the user logs out of your app, log them out of UniSignIn too:

window.unisignin.cmd.push(['client_logout'])

Step 2: Push profile data from your server

Set up the import

  1. Go to Data Management → Data Exchange and click New.
  2. Set Exchange Type to Import Data.
  3. In Link identifiers, enter the name of the email field in your data, e.g. email, and choose email as the UniSignIn field.
  4. In Map data fields, map each field you send to a UniSignIn profile field, e.g. plan → Plan. Map the date the user registered in your system, e.g. created_at, to Registration Date. It is used when the user is created in UniSignIn and doesn't change existing users. Add custom fields first in Data Management → User Data → Data Schema if you need them, see Profile Fields.
  5. Turn on Enable, save, and copy the exchange ID.

Send the data

Send one user or a list of up to 100 users per request:

curl -X POST https://secure.signinservice.com/api/v1/user/EXCHANGE_ID \
  -H "Authorization: Bearer SECRET_KEY" \
  -H "x-license: YOUR_LICENSE" \
  -H "Content-Type: application/json" \
  -d '[{"email": "[email protected]", "created_at": "2024-05-01T09:30:00Z", "plan": "pro", "role": "admin", "company": "Acme"}]'

The response tells you how many users were updated and how many were new:

{ "status": 1, "updated": 1, "created": 0 }
  • A user who doesn't exist in UniSignIn yet is created, so you can push all your existing users before they next log in.
  • Only the fields you send are changed. Fields you leave out keep their current values.
  • The data can be used in segments shortly after it is sent.

Send data whenever it changes in your system, e.g. when a user upgrades their plan or changes their role. To load your existing users, send them in batches of 100.

Step 3: Track activity in your app

Send an event when a user does something you want to segment or report on:

window.unisignin.cmd.push(['trace', 'project_created'])
window.unisignin.cmd.push(['trace', 'teammate_invited'])

Use short lowercase names. Events are then available in segments with Actions (last 30 days) contains project_created.

To label a user, add a tag:

window.unisignin.cmd.push(['tag', 'power-user'])

Tags appear in the Tags (last 30 days) profile field. See Events and the JavaScript API.

Example: Laravel

Share the SSO token with your layout for logged-in users:

// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\View;

public function boot(): void
{
    View::composer('layouts.app', function ($view) {
        $user = auth()->user();
        $view->with('unisigninToken', $user ? base64_encode(json_encode([
            'email' => $user->email,
            'first_name' => $user->first_name,
            'last_name' => $user->last_name,
            'full_name' => $user->name,
            'reg_date' => $user->created_at->toIso8601String(),
            'public_key' => config('services.unisignin.sso_public'),
            'signature' => hash('sha512', $user->email . '-' . config('services.unisignin.sso_private')),
        ])) : null);
    });
}
{{-- resources/views/layouts/app.blade.php --}}
@if ($unisigninToken)
<script>
window.unisignin = window.unisignin || {};
window.unisignin.cmd = window.unisignin.cmd || [];
window.unisignin.cmd.push(['getUser', function (user) {
  if (!user.isLogin) window.unisignin.cmd.push(['sso_login', @json($unisigninToken), function () {}]);
}]);
</script>
@endif

Push profile data when a user changes, from a queued job:

// app/Jobs/SyncUserToUniSignIn.php
use Illuminate\Support\Facades\Http;

public function handle(): void
{
    Http::withToken(config('services.unisignin.secret'))
        ->withHeaders(['x-license' => config('services.unisignin.license')])
        ->post('https://secure.signinservice.com/api/v1/user/' . config('services.unisignin.exchange_id'), [[
            'email' => $this->user->email,
            'created_at' => $this->user->created_at->toIso8601String(),
            'plan' => $this->user->plan,
            'role' => $this->user->role,
            'company' => $this->user->team?->name,
        ]])
        ->throw();
}
// app/Observers/UserObserver.php
public function saved(User $user): void
{
    SyncUserToUniSignIn::dispatch($user);
}

Load existing users once with a console command:

User::query()->chunk(100, function ($users) {
    Http::withToken(config('services.unisignin.secret'))
        ->withHeaders(['x-license' => config('services.unisignin.license')])
        ->post('https://secure.signinservice.com/api/v1/user/' . config('services.unisignin.exchange_id'),
            $users->map(fn ($user) => ['email' => $user->email, 'created_at' => $user->created_at->toIso8601String(), 'plan' => $user->plan])->all());
});

Log out of UniSignIn on your logout page or button:

window.unisignin.cmd.push(['client_logout'])

Stay ahead in first-party data

Identity, consent, audience, and subscription insights for publishers. A few emails a month, no spam.

By subscribing you agree to our privacy policy.