Passwordless Authentication
Magic link and SMS OTP passwordless login flows with the TypeScript SDK.
Passwordless Authentication
The SDK supports two passwordless authentication methods: magic links (email) and SMS OTP (phone). Both eliminate the need for users to remember passwords.
Magic link login
loginWithMagicLink()
Send a magic link to the user's email. Clicking the link authenticates them and redirects to your application.
loginWithMagicLink(params: MagicLinkParams): Promise<{ flowId: string }>Parameters
| Name | Type | Required | Description |
|---|---|---|---|
email | string | yes | User's email address |
returnUrl | string | no | URL to redirect to after clicking the link |
Returns
Promise<{ flowId: string }> -- Flow ID for tracking. The actual magic link is sent via email.
Basic usage
import { AvnologyId } from "@avnology/sdk-typescript";
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
});
// Send magic link
const { flowId } = await client.loginWithMagicLink({
email: "[email protected]",
returnUrl: "https://myapp.com/dashboard",
});
showMessage(
"We sent a login link to [email protected]. " +
"Click the link in your email to sign in."
);Handling the magic link callback
When the user clicks the magic link, they are redirected to your returnUrl with the session already established.
// On your callback/return page
const session = await client.getSession();
if (session) {
console.log("Logged in via magic link:", session.identity.email);
router.navigate("/dashboard");
} else {
showError("Magic link expired or invalid. Please try again.");
router.navigate("/login");
}SMS OTP login
loginWithSms()
Send a one-time password via SMS to the user's phone number.
loginWithSms(params: SmsLoginParams): Promise<{ flowId: string }>Parameters
| Name | Type | Required | Description |
|---|---|---|---|
phone | string | yes | Phone number in E.164 format (e.g., "+15550100") |
Returns
Promise<{ flowId: string }> -- Flow ID required to verify the code.
verifySmsCode()
Verify the SMS OTP code to complete authentication.
verifySmsCode(params: VerifySmsCodeParams): Promise<Session>Parameters
| Name | Type | Required | Description |
|---|---|---|---|
flowId | string | yes | Flow ID from loginWithSms() |
code | string | yes | 6-digit code sent via SMS |
Returns
Promise<Session> -- The authenticated session.
Full flow
import {
AvnologyId,
InvalidCodeError,
ExpiredFlowError,
RateLimitError,
} from "@avnology/sdk-typescript";
const client = new AvnologyId({
baseUrl: "https://api.id.avnology.com",
clientId: "app_abc123",
});
// Step 1: Send SMS code
try {
const { flowId } = await client.loginWithSms({
phone: "+15550100",
});
showMessage("Enter the 6-digit code sent to your phone.");
// Step 2: Verify the code (user enters it)
const code = await getUserInput("Verification code:");
const session = await client.verifySmsCode({ flowId, code });
console.log("Logged in:", session.identity.phone);
redirectToDashboard();
} catch (error) {
if (error instanceof InvalidCodeError) {
showError(`Invalid code. ${error.attemptsRemaining} attempts remaining.`);
} else if (error instanceof ExpiredFlowError) {
showError("Code expired. Please request a new one.");
} else if (error instanceof RateLimitError) {
showError(`Too many attempts. Wait ${error.retryAfter} seconds.`);
}
}Resend SMS code
// If the user didn't receive the code, resend it
const { flowId: newFlowId } = await client.loginWithSms({
phone: "+15550100",
});
showMessage("A new code has been sent to your phone.");Passwordless registration
Both magic link and SMS OTP can be used for registration as well. If the user does not have an account, one is created automatically during the passwordless flow.
// This creates a new account if one doesn't exist
const { flowId } = await client.loginWithSms({
phone: "+15550100",
});
const session = await client.verifySmsCode({ flowId, code: "482901" });
// The session will have a newly created identity if this was a new user
if (!session.identity.name?.first) {
// Redirect to profile completion page
router.navigate("/onboarding");
}When to use which method
| Method | Best for | Considerations |
|---|---|---|
| Magic link | Desktop web, email-first flows | User must switch to email client |
| SMS OTP | Mobile apps, phone-first flows | Requires valid phone number; SMS has delivery costs |
| Passkey | Maximum security, repeat users | Requires device with biometric/PIN support |
| Password | Broadest compatibility | Weakest security, breach risk |
Common errors
| Error class | HTTP status | When |
|---|---|---|
InvalidCodeError | 400 | Wrong SMS verification code |
ExpiredFlowError | 410 | Magic link or SMS code expired |
RateLimitError | 429 | Too many SMS/email requests |
ValidationError | 422 | Invalid phone number format |
MethodDisabledError | 403 | Passwordless is disabled for this app/org |