Avnology ID
SDKsTypeScript SDKAuthentication

Login

Authenticate users with email/password, passkeys, social providers, magic links, and SMS OTP using the TypeScript SDK.

Login

The TypeScript SDK provides multiple login methods. Each method initiates an authentication flow and returns a Session on success.

login()

Authenticate with email and password.

login(params: LoginParams): Promise<Session>

Parameters

NameTypeRequiredDescription
emailstringyesUser's email address
passwordstringyesUser's password
organizationIdstringnoScope login to a specific organization

Returns

Promise<Session> -- The authenticated session with identity data and expiry.

Basic usage

import { AvnologyId } from "@avnology/sdk-typescript";

const client = new AvnologyId({
  baseUrl: "https://api.id.avnology.com",
  clientId: "app_abc123",
});

const session = await client.login({
  email: "[email protected]",
  password: "SecurePassword123!",
});

console.log(session.id);              // "ses_abc123..."
console.log(session.identity.id);     // "usr_abc123..."
console.log(session.identity.email);  // "[email protected]"
console.log(session.expiresAt);       // "2026-04-09T12:00:00Z"
console.log(session.authenticatorAssuranceLevel); // "aal1"

Organization-scoped login

Restrict authentication to users within a specific organization. If the user is not a member, the login is rejected.

const session = await client.login({
  email: "[email protected]",
  password: "SecurePassword123!",
  organizationId: "org_abc123",
});

console.log(session.identity.organizationId); // "org_abc123"

Error handling

import {
  InvalidCredentialsError,
  AccountLockedError,
  MfaRequiredError,
  AccountDisabledError,
  RateLimitError,
  ValidationError,
} from "@avnology/sdk-typescript";

try {
  const session = await client.login({ email, password });
} catch (error) {
  if (error instanceof InvalidCredentialsError) {
    // Wrong email or password. Do not reveal which one is wrong.
    showError("Invalid email or password.");
  } else if (error instanceof AccountLockedError) {
    // Too many failed attempts. Account temporarily locked.
    showError(
      `Account locked due to too many failed attempts. ` +
      `Try again in ${error.retryAfter} seconds.`
    );
  } else if (error instanceof MfaRequiredError) {
    // First factor succeeded, but MFA is required.
    // Redirect user to MFA challenge with the flow ID.
    redirectToMfa(error.flowId, error.availableMethods);
    // error.availableMethods: ["totp", "webauthn", "recovery_code"]
  } else if (error instanceof AccountDisabledError) {
    // The account has been administratively disabled.
    showError("This account has been deactivated. Contact support.");
  } else if (error instanceof RateLimitError) {
    showError(`Too many requests. Try again in ${error.retryAfter} seconds.`);
  } else if (error instanceof ValidationError) {
    // Invalid input (e.g., malformed email).
    showFieldErrors(error.fieldErrors);
    // error.fieldErrors: [{ field: "email", message: "Invalid email format" }]
  }
}

loginWithPasskey()

Authenticate using a FIDO2 passkey or security key. This triggers the browser's WebAuthn credential selection dialog.

loginWithPasskey(params?: LoginWithPasskeyParams): Promise<Session>

Parameters

NameTypeRequiredDescription
organizationIdstringnoScope login to a specific organization
mediation"conditional" | "required" | "optional"noWebAuthn mediation hint (default: "optional")

Returns

Promise<Session> -- The authenticated session at AAL1 or AAL2 depending on passkey type.

Basic usage

try {
  const session = await client.loginWithPasskey();
  console.log(session.identity.email);
  console.log(session.authenticatorAssuranceLevel); // "aal2" for device-bound passkeys
} catch (error) {
  if (error.name === "NotAllowedError") {
    // User cancelled the WebAuthn dialog
    showError("Passkey authentication was cancelled.");
  }
}

Conditional UI (autofill)

Use conditional mediation to offer passkey autofill alongside the password field. The browser will suggest passkeys in the username field autocomplete dropdown.

// Start conditional passkey login (non-blocking)
const session = await client.loginWithPasskey({
  mediation: "conditional",
});

loginWithProvider()

Initiate social login with an OAuth/OIDC provider. This redirects the browser to the provider's login page.

loginWithProvider(provider: string, params?: LoginWithProviderParams): void

Parameters

NameTypeRequiredDescription
providerstringyesProvider identifier: "google", "github", "microsoft", "apple"
returnUrlstringnoURL to redirect to after login (default: current page)
organizationIdstringnoScope login to a specific organization

Returns

void -- This method redirects the browser. It does not return.

Basic usage

// Redirect to Google login
client.loginWithProvider("google");

// With return URL
client.loginWithProvider("github", {
  returnUrl: "https://myapp.com/dashboard",
});

// Organization-scoped
client.loginWithProvider("microsoft", {
  organizationId: "org_abc123",
});

Handling the callback

After the user authenticates with the provider, they are redirected back to your application. The session is automatically established via cookies.

// On your callback page or return URL
const session = await client.getSession();
if (session) {
  console.log("Logged in as:", session.identity.email);
  router.navigate("/dashboard");
}

Send a passwordless magic link to the user's email.

loginWithMagicLink(params: MagicLinkParams): Promise<{ flowId: string }>

Parameters

NameTypeRequiredDescription
emailstringyesEmail address to send the magic link to

Returns

Promise<{ flowId: string }> -- The flow ID for tracking. The user must click the link in their email.

Basic usage

const { flowId } = await client.loginWithMagicLink({
  email: "[email protected]",
});

showMessage("Check your email for a login link.");

// The magic link URL contains a token that, when clicked,
// authenticates the user and redirects to your app.

loginWithSms()

Initiate passwordless login via SMS one-time password.

loginWithSms(params: SmsLoginParams): Promise<{ flowId: string }>

Parameters

NameTypeRequiredDescription
phonestringyesPhone number in E.164 format (e.g., "+15550100")

Returns

Promise<{ flowId: string }> -- The flow ID needed to verify the SMS code.

Basic usage

// Step 1: Send the SMS code
const { flowId } = await client.loginWithSms({
  phone: "+15550100",
});

showMessage("Enter the 6-digit code sent to your phone.");

// Step 2: Verify the code
const session = await client.verifySmsCode({
  flowId,
  code: "482901", // User-entered code
});

console.log(session.identity.phone); // "+15550100"

verifySmsCode()

Complete an SMS OTP login by verifying the code sent to the user's phone.

verifySmsCode(params: VerifySmsCodeParams): Promise<Session>

Parameters

NameTypeRequiredDescription
flowIdstringyesFlow ID from loginWithSms()
codestringyes6-digit verification code

Returns

Promise<Session> -- The authenticated session.

Error handling

import { InvalidCodeError, ExpiredFlowError } from "@avnology/sdk-typescript";

try {
  const session = await client.verifySmsCode({ flowId, code });
} catch (error) {
  if (error instanceof InvalidCodeError) {
    showError("The code you entered is incorrect. Please try again.");
    // error.attemptsRemaining: number of attempts left
  } else if (error instanceof ExpiredFlowError) {
    showError("This code has expired. Please request a new one.");
  }
}

Common errors

All login methods can throw these errors:

Error classHTTP statusWhen
InvalidCredentialsError401Wrong email/password
AccountLockedError423Too many failed attempts
AccountDisabledError403Account administratively disabled
MfaRequiredError403First factor OK, MFA needed
RateLimitError429Too many requests
ValidationError422Invalid input fields
InvalidCodeError400Wrong SMS/magic link code
ExpiredFlowError410Auth flow expired
NetworkErrorN/AConnection failure

See also

On this page