PortalLoginMethod

Signing a member into the portal through the platform — the button, the handshake the core mints, how the connector completes it from its inbound side, and what the member sees.

Subscriby\Connector\Contracts\Ports\PortalLoginMethod. Bound by portal_login.

A member who bought through the platform has no password. The portal offers one sign-in button per installed connector with this port; the core mints a handshake (a two-sided proof with a token and a lifetime), the connector says how the member presents it on the platform, and the connector's inbound side completes it with the account that answered. The core polls the handshake and signs the member in when it completes.

Methods

MethodCalled whenReturns
button()The portal's sign-in sheet lists the methods of the project's installed connectors; the kit.PortalLoginButton
begin(installation, ProjectRef, HandshakeRef)The member taps the button: the core has opened the handshake and asks how the sign-in starts.PortalLoginStart

button()

PortalLoginButton: label (a translation key, "Continue with Telegram") and icon (a key from Subscriby's connector icon set, usually your connector's own). Both non-empty.

begin()

The HandshakeRef carries the handshake's id, purpose (HandshakePurpose::PortalLogin) and the token the member must present. Answer a PortalLoginStart:

  • token: echo the token.
  • url: where the member goes to present it, usually InstallationLifecycle::startLink($installation, $payload) with the token in the payload.
  • instructions: what to do by hand when the link cannot open (type a command with the token in a chat with the installation).

The installation is the project's live installation on your connector and the ProjectRef names whose portal it is, so a project-bound handshake can only complete through that project's own installation.

Completing it

The core never sees the platform; your inbound handler does. When an account presents the token (opens the deep link, types the command), your handler:

  1. asks Core\Identities::isHandshakeToken($token) when the token arrived as a typed word, so a wizard answer that happens to look like a code is left to its wizard;
  2. builds an IdentityRecord for the account that answered (what IdentityResolver::adopt() would file);
  3. calls Core\Identities::completeHandshake($token, $record, $seenBy) with the installation that heard the account.

The core decides what the handshake was for: for a portal login it finds or creates the account's member in the handshake's project, links the identity, and answers a HandshakeCompletion with the subjectName and a returnUrl the connector may show the member ("Open the portal"). HandshakeRefused is thrown when the token names no pending handshake, the account already belongs to someone else, another project's installation heard it, or the purpose is not completed through this call; tell the member the link expired and offer a fresh start.

The same handshake, other purposes

Creator links (a creator adding an account under Linked accounts), member links from the portal's Connected accounts, recovery relinks and backup identities are the same table and the same completeHandshake() call with other HandshakePurposes. Your inbound handler need not know the purpose: it presents the account, and the core writes the right link.

How Telegram does it

The portal shows the bot's deep link carrying the handshake's auth_ payload; the bot's /start routes it to the customer handler, which offers the chat's identity back to the core. The typed command is the manual route for Telegram Web, where deep links do not always open.

What the kit checks

portal_login.button: button() returns a label and an icon that are both non-empty.

Only the token proves anything

Never sign a member in from a display name, a username or an external id you were told in a message. The handshake token is the proof; the account that presents it in a private conversation with the installation is the account that gets linked.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request