Synq Docs
Guides

Test sign-ins

Sign in as a made-up GitHub or Google account in your end-to-end tests, with the age, repositories or Workspace domain your rules look at, everywhere but production.

An app that judges people by their GitHub or Google account, such as a free service that wants a GitHub account at least a month old, needs tests that sign in as a young account, an old one, a Google Workspace account and a personal one. Real accounts can't be made to order. Test sign-ins can: turn them on for an app, and its sign-ins also offer test, which signs in as a made-up account your test describes.

They exist on Synq's stages other than production: preview, where your end-to-end tests run, and a local stack. Production never offers them, and refuses the switch.

Turning them on

Make or change the app with test_sign_ins:

{ "test_sign_ins": true }

A machine app signs no one in, so it has none. From an MCP host or an agent, set_app_test_sign_ins turns them on or off (MCP tools). The audit log records each change as app.updated.

A test sign-in stands in for GitHub or Google, the providers the app takes: an app that takes GitHub and Google alone offers both, one that takes Google alone offers Google. The brand needn't have the provider turned on.

The account a test describes

FieldWhat it is
providergithub or google.
accountThe account's id for this test: lowercase letters, digits and dashes, at most 40. The same id is the same person again.
username, email, nameOptional. GitHub's login, the address the provider gives (never verified at Synq) and a name.
account_typeGitHub: User, Organization or Bot. User unless named.
account_age_daysGitHub: how many days old the account is, 365 unless named. Or created_at, an ISO 8601 time, instead.
public_repos, followersGitHub: 1 and 0 unless named.
email_verifiedGoogle: whether Google checked the address, true unless named.
workspace_domainGoogle: the Workspace domain. A personal account unless named.

The person it signs in is an ordinary user of the brand, with an identity at the provider. Their linked_accounts entry carries what the test said, and test: true:

{
  "provider": "github",
  "subject": "test-young-dev",
  "username": "young-dev",
  "details_read_at": "2026-10-23T09:12:40.000Z",
  "account_type": "User",
  "created_at": "2026-10-11T09:12:40.000Z",
  "public_repos": 0,
  "followers": 0,
  "test": true
}

On the hosted page

The sign-in page lists Test sign-in beside the other ways. Its form takes the fields above, so a browser test fills it in and submits it like any other sign-in.

Headless, on your app's own screens

An app that signs people in on its own screens gets tokens with no browser at all: synq_method=test, with each field as synq_test_<field>, on /authorize-challenge, signs in at once and answers with the authorization code. With @synqauth/js:

import { createSynqClient } from '@synqauth/js'

// Your test app: a native app with own_ui_sign_in and test_sign_ins on.
const synq = createSynqClient({ issuer, clientId, redirectUri })
const result = await synq.startSignIn().test.signIn({
  provider: 'github',
  account: 'young-dev',
  accountAgeDays: 12,
  publicRepos: 0,
})
// result.status is 'signed-in', with the session's tokens.

The app needs own_ui_sign_in for this, as for any sign-in on its own screens. A test app of its own, beside your real one, keeps both settings out of the app people use.

What keeps them apart from real accounts

  • Production never offers them, whatever an app says.
  • Their subject starts with test-, which no GitHub or Google account's ever does, so a test sign-in never signs in as a real account or takes one over.
  • Their address is never verified at Synq and never links to another account, whatever email_verified says: that is Google's word in the details alone.
  • Every linked account they make says test: true. Refuse those wherever real people sign in, if your code ever runs against a stage that has them.

On this page