@mmgt-cloud/auth-client
v1.2.0
Published
Universal TypeScript client for the auth service.
Maintainers
Readme
@mmgt-cloud/auth-client
Universal TypeScript client for the auth service. It targets browsers, SSR, and
Node runtimes with a standards-based fetch implementation. The package wraps
the app-facing auth API: email/password auth, token refresh, profile and session
management, social login callbacks, 2FA, magic links, activity logs, and passkeys.
Install
pnpm add @mmgt-cloud/auth-clientNo .npmrc, GitHub account, or access token is required. The package supports modern browsers and Node.js 22+ with standards-based fetch; passkey helpers require WebAuthn. Public exports include AuthClient, token stores, typed errors, WebAuthn helpers, and request/response types. Licensed under MIT.
import { AuthClient, MemoryTokenStore } from "@mmgt-cloud/auth-client";
const auth = new AuthClient({
baseUrl: "https://api.example.invalid/auth",
appId: "00000000-0000-0000-0000-000000000001",
tokenStore: new MemoryTokenStore()
});Email/password login
const result = await auth.login({ email: "[email protected]", password: "correct horse battery staple" });
switch (result.kind) {
case "success":
await auth.getProfile();
break;
case "requires_2fa":
await auth.verify2FALogin({ temp_token: result.tempToken, code: "123456" });
break;
case "requires_2fa_setup":
// Keep enrollment credentials in a separate memory-only client.
// Do not put these restricted credentials into the application session.
const enrollment = new AuthClient({
baseUrl: auth.baseUrl,
appId: auth.appId,
tokenStore: new MemoryTokenStore(),
autoRefresh: false
});
await enrollment.setTokens({ accessToken: result.accessToken, refreshToken: result.refreshToken });
const methods = await enrollment.get2FAMethods();
if (methods.totp_enabled && methods.available_methods.includes("totp")) {
const setup = await enrollment.generate2FA();
// Display setup.qr_code_url and collect a fresh code from the user.
void setup;
}
break;
case "password_expired":
// Show a password update flow.
break;
}To complete TOTP enrollment, call enrollment.verify2FASetup(code) and then
enrollment.enable2FA(). Display the returned recovery codes once, clear the
enrollment client's tokens and sign in again to complete MFA. Enrollment tokens
expire after ten minutes and cannot refresh or access other platform services.
Choose only a method returned by the application's current configuration.
Email-code login/registration and magic links return the same explicit login
outcomes. A password_expired result requires the password-reset flow.
Social login
auth.redirectToSocialLogin("apple", `${window.location.origin}/auth/callback`);
// On /auth/callback:
const redirect = await auth.handleAuthRedirect(window.location.href);
if (redirect.requiresMerge && redirect.mergeToken) {
// Sign in to the existing account and complete its MFA first. Then:
await auth.request<{ message: string }>("/merge/link-authenticated", {
method: "POST", auth: true, body: { merge_token: redirect.mergeToken }
});
}Inspect error, requires2FA, requiresTwoFASetup and requiresMerge before
treating the callback as a completed login. A one-time oauth_code is exchanged
before session persistence. Enrollment results are deliberately not persisted;
use a separate memory client as above. Provider merge with only a password is
insufficient when the existing account requires MFA. These are browser flows;
the public Swift SDK uses its registered OIDC and native account-provider flows.
Account linking is a protected backend redirect and cannot be started with a
plain browser location.assign, because the browser cannot attach the bearer
token to that navigation. Use createSocialLinkRequest() from a server-side
context, a BFF route, or a trusted same-origin bridge that can forward the
returned URL and headers to /auth/{provider}/link.
const link = await auth.createSocialLinkRequest("github", "https://app.example.com/auth/link-callback");Passkeys
await auth.registerPasskey("MacBook passkey");
await auth.passwordlessLogin();The WebAuthn wire contract matches the auth service directly. The helper functions convert base64url JSON challenge payloads to browser credential options and serialize the browser credential response back to JSON.
Token storage
Only two nonempty token strings form a complete token pair. An expired-password
response returns kind: "password_expired" even if the server includes empty
token fields; start the password reset flow. Empty login, refresh or OAuth code
exchange results are not persisted as a session. MFA/enrollment results also
require completing their own flow before opening authenticated screens.
Email-code helpers are requestLoginCode(email), resendLoginCode(email) and
verifyLoginCode({ email, code }). Registration uses startRegistrationWithCode,
resendRegistrationCode and verifyRegistrationCode. Verification can still
require MFA. An accepted email request does not prove inbox delivery.
Use MemoryTokenStore for short-lived browser state, SSR, and tests. Production
frontends should prefer an httpOnly-cookie or BFF-backed token strategy when
possible. If a pure SPA deliberately accepts the XSS tradeoff, the package also
exports createUnsafeBrowserLocalStorageTokenStore().
Profile and provider facts
getProfile() and updateProfile() expose pending_email when a new address is
awaiting confirmation; email remains the current address. Linked social accounts
include optional email_verified and email_is_private_relay observations.
Undefined means the response did not supply that fact. These fields do not grant
permissions and do not replace backend checks. Profile/provider reads need
user:read, profile updates need user:write, and activity operations log:read.
Prefer JSON activity export to inspect its truncated flag; exports are capped
at 10,000 records, and the CSV overload returns text without header metadata.
