Skip to Content
ConceptsProviders

Providers

Every login method users actually want, with the per-provider quirks hidden behind a single API.

The catalog

ProviderStandardWhat’s special
GoogleOIDCThe least surprising. PKCE optional.
AppleOAuth-2 (non-standard)client_secret is a signed ES256 JWT from a .p8 key. response_mode=form_post. PKCE supported.
Microsoft (Azure AD)OIDCTenant-scoped (single org) or multi-tenant.
DiscordOAuth-2No OIDC. Profile via GET /users/@me.
FacebookOAuth-2No OIDC. Profile via GET /me?fields=….
X (Twitter v2)OAuth-2 + PKCENewer API; not legacy 1.1.
TelegramCustom widgetHash-verified payload; per-bot, requires explicit domain binding.
MatricaVendor SDKCarries linked wallets and social accounts the user already aggregated there.
Solana walletsSigned messagePhantom, Solflare, Backpack, MWA on Android. No transaction.

From the App-developer view, you ask for provider: 'google' and Synq handles everything else. The “what’s special” column matters mostly for BYO setup.

Picking which providers to enable

Two levers on the Brand record:

  • providerOrder: string[] — default order shown in the sign-in modal. Default ['google', 'apple', 'discord', 'microsoft'].
  • BYO connections — for each provider you want to ship in production at any meaningful scale, set up a per-Brand connection via BYO credentials.

Hide a provider by removing it from providerOrder or disabling its BYO connection.

Provider-by-provider notes

Google

The least surprising. Set up via Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client ID (type: Web application).

Redirect URI: https://synq.id/oauth/google/<brand.oauthCallbackId>/callback.

Authorized JavaScript origin: https://synq.id.

Synq requests the openid email profile scopes by default. You don’t need to pre-request additional scopes; Synq normalizes.

Apple

The trickiest provider, by an order of magnitude. Synq handles all of the trickiness; you only need to know this if you ship BYO Apple.

Apple’s “client secret” is a signed JWT generated fresh on every token exchange. You need three things from Apple Developer:

  • Team ID — your developer team identifier.
  • Service ID — created under Apple → Certificates, Identifiers & Profiles → Identifiers → Services IDs. This is your clientId.
  • Key ID + private key — created under Keys → enable Sign in with Apple → download the .p8 file. The Key ID is the filename; the contents are PEM.

Your BYO Apple connection in Synq stores all four:

{ type: 'apple', enabled: true, config: { teamId: 'XXXXXXXXXX', clientId: 'com.acme.web', keyId: 'YYYYYYYYYY', privateKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----', } }

Synq mints the JWT (ES256, expires every 60 seconds) at each token exchange. Apple is strict — extra claims like jti or nbf in the JWT will fail with invalid_client. Synq matches Apple’s spec exactly.

Redirect URI on the Service ID: https://synq.id/oauth/apple/<brand.oauthCallbackId>/callback.

Set the email source to “Forward to” your support email if you let users use private-relay addresses. Synq passes through the private-relay email as-is.

Microsoft (Azure AD)

Standard OIDC over login.microsoftonline.com. Set up via Azure Portal → App registrations → New registration.

  • Single tenant: your tenantId is your Azure AD tenant.
  • Multi-tenant: tenantId = 'common'. You will need to register your app’s redirect URI under each tenant if those tenants are configured to require admin consent.

Redirect URI: https://synq.id/oauth/microsoft/<brand.oauthCallbackId>/callback.

In the App Registration, also set the API permissions: openid, email, profile, User.Read. Grant admin consent on your tenant if your org requires it.

Discord

OAuth-2 only — no OIDC. Synq fetches the profile from GET https://discord.com/api/users/@me after exchange.

Set up via Discord Developer Portal → New Application → OAuth2.

Redirect URI: https://synq.id/oauth/discord/<brand.oauthCallbackId>/callback.

Default scopes: identify (always), email (when your App requests email from Synq).

Facebook

OAuth-2 with provider-specific quirks. Set up via Facebook for Developers → Create App.

Redirect URI: https://synq.id/oauth/facebook/<brand.oauthCallbackId>/callback.

Most apps want the email and public_profile permissions. You must publish your Facebook App (move it out of dev mode) before it can grant email to non-developers.

X (Twitter v2)

OAuth 2.0 with PKCE. Set up via X Developer Portal → Projects & Apps → User authentication settings.

  • App type: confidential or public — public is fine if you only need user sign-in.
  • Permissions: read users.
  • Callback URLs: https://synq.id/oauth/x/<brand.oauthCallbackId>/callback.

X requires explicit scopes: tweet.read users.read offline.access. Synq sets these for you.

Telegram

Telegram does not use OAuth. Sign in with Telegram works via the Telegram Login Widget: the user clicks a Telegram-hosted button, authorizes the bot, and Telegram POSTs a signed payload back.

Two prerequisites:

  1. A bot. Create via @BotFather . You get a bot username and a bot token. Save both.
  2. Domain binding. In BotFather, /setdomain to bind your bot to a domain. Telegram will only allow login widgets on that domain. You bind to synq.id (since that’s the domain serving the widget); your end users don’t see the binding.

Synq’s per-Brand Telegram connection stores { botUsername, botToken }. Synq verifies the Telegram payload’s HMAC against the bot token on receipt.

One bot per Brand. If you have multiple Brands, each Brand needs its own bot. The default Synq bot is shared and works only on synq.id-hosted sign-in surfaces.

Matrica

Matrica is the “I already have wallets and socials” provider — users who have aggregated their identity on Matrica can sign in to your app via Matrica and carry over their linked wallets and social accounts.

Set up via Matrica Developer Console .

Redirect URI: https://synq.id/oauth/matrica/<brand.oauthCallbackId>/callback.

Use Matrica when your audience overlaps heavily with the Solana community.

Solana wallets

Not an OAuth provider, but exposed through the same provider: 'solana' API. The flow:

  1. User picks “Sign in with Wallet” in the sign-in modal.
  2. Synq generates a challenge (see Security).
  3. Wallet signs the message.
  4. Synq verifies the signature and the user is signed in.

Supports: Phantom, Solflare, Backpack, Glow, anything that implements the Wallet Standard. On Android, supports MWA (Mobile Wallet Adapter). On iOS, deep-links to Phantom.

Wallets are first-class as both a sign-in method and as a linkable identity provider for users who already signed in with OAuth. See Identity model.

How a Synq integrator triggers each provider

The provider is just a parameter. The SDK call is the same shape for every one of them:

// @synqid/react const { signIn } = useSynq() await signIn({ provider: 'google' }) await signIn({ provider: 'apple' }) await signIn({ provider: 'solana' })
// Raw OIDC const params = new URLSearchParams({ client_id, redirect_uri, response_type: 'code', scope: 'openid profile email', state, nonce, code_challenge, code_challenge_method: 'S256', provider: 'google', // <-- preselect a provider; skips Synq's chooser }) res.redirect(`https://synq.id/oauth2/authorize?${params}`)

Omitting provider shows Synq’s branded sign-in modal with the full provider list. Including it skips the chooser entirely.

Linking vs signing in

A user who is already signed in can link another provider to their identity. The flow is identical to sign-in, except Synq attaches the new provider to the existing user instead of creating a new one.

From your code:

await synq.signIn({ provider: 'apple' }) // sign in or create user await synq.link({ provider: 'apple' }) // requires current session

If a sign-in returns a user that already has an email collision with another user (e.g. the same email at Google and Apple, both already linked to different users), Synq surfaces a conflict error and your app should walk the user through a merge flow with confirmation from both sides.

Mental model summary

  • One API. provider: 'X' is the only thing that changes between providers from an App’s perspective.
  • BYO is per-provider. Each connection stores the credentials Synq needs to act on your brand’s behalf.
  • Apple is special. Anytime Apple sign-in fails in confusing ways, the answer is the JWT shape.
  • Telegram is special. It’s a bot + widget, not OAuth. Per-Brand bot.
  • Solana is a provider too. Same signIn({ provider: 'solana' }) call; signed message under the hood.
Last updated on