npm package: @nexusrt/nexus-auth
Description: Universal TypeScript SDK for the Nexus authentication system
Latest version: 1.1.0

# JobTrk Auth SDK

A universal, framework-agnostic TypeScript SDK for the JobTrk authentication system.  
Works in React, Vue, Svelte, Angular, vanilla JS — anywhere that runs in a browser.

---

## Installation

```bash
npm install jobtrk-auth-sdk
```

---

## Quick Start

```ts
import { createAuthClient, SignInStatus } from "jobtrk-auth-sdk";

const auth = createAuthClient({
  baseUrl: "https://auth.yourapp.com", // defaults to https://auth.jobtrk.com
});
```

> **`createAuthClient` is the recommended way to use the SDK.**  
> It pre-binds `baseUrl` to every method so you never need to pass it manually.

---

## Session Modes

The SDK supports two ways to persist a login:

| Mode | How it works | When to use |
|---|---|---|
| **JWT** | Server returns an `access_token` + sets an HttpOnly refresh-token cookie | Stateless APIs, microservices |
| **Session** | Server sets an HttpOnly session cookie | Traditional server-rendered apps |

In both modes an **access token** is available so you can authenticate with downstream services.

### Restore session on app startup

```ts
// JWT mode — uses the HttpOnly refresh-token cookie to get a new access token
const user = await auth.token.refresh();
if (user) {
  console.log("Logged in as", user.email);
}

// Session mode — read the current user from the server
const user = await auth.session.getUser();
```

---

## Social Sign-In

Redirects the browser to the provider's OAuth flow.

```ts
auth.social.signInWithGoogle();
auth.social.signInWithGithub();
auth.social.signInWithLinkedIn();
auth.social.signInWithOkta();
```

---

## Email + Password

### Sign up

```ts
await auth.email.signUp({ email, password });
```

### Sign in (no MFA)

```ts
const result = await auth.email.signIn({ email, password });
// result.access_token is set — user is signed in
```

### Sign in with Email MFA

```ts
const result = await auth.email.signIn({ email, password });

if (result.status === SignInStatus.MFA_REQUIRED) {
  const sessionId = result.mfa!;

  // Prompt the user for the code emailed to them
  await auth.email.verifyMfa({ sessionId, code: userEnteredCode });
}
```

### Sign in with TOTP

```ts
const result = await auth.email.signIn({ email, password });

if (result.status === SignInStatus.TOTP_REQUIRED) {
  const sessionId = result.mfa!;

  // Prompt the user for their authenticator app code
  await auth.totp.verifySignIn({ sessionId, code: userEnteredCode });
}
```

---

## Email Magic Link

```ts
// 1. Send the magic link
const { mfa: sessionId } = await auth.magicLink.send(email);

// 2. User receives an email with a code — verify it
await auth.magicLink.verify({ sessionId, code: userEnteredCode });
```

---

## SSO (Multi-Tenant)

### Organisation admin — register your IDP once

```ts
await auth.sso.registerProvider({
  providerName:     "Acme Corp",
  providerEndEmail: "acme.com",
  clientId:         "...",
  clientSecret:     "...",
  issuer:           "https://idp.acme.com",
  callbackUrl:      "https://yourapp.com/auth/callback",
});
```

### End user — sign in via their org's IDP

```ts
const { auth_url } = await auth.sso.signIn(email);
window.location.href = auth_url; // redirect to org's IDP
```

---

## Password Management

### Reset password (authenticated user)

```ts
await auth.password.reset({
  oldPassword: "current-password",
  newPassword: "new-password",
});
```

### Forgot password

```ts
// 1. Send reset code to email
const { mfa: sessionId } = await auth.password.forgot(email);

// 2. User enters code from email
await auth.password.confirmForgot({
  sessionId,
  code:     userEnteredCode,
  password: newPassword,
});
```

---

## TOTP Setup

```ts
// 1. Start registration — display the QR code / secret to the user
const { totp } = await auth.totp.setup();
// totp = QR code data or secret string — render as a QR code

// 2. User scans with their authenticator app and enters the first code
await auth.totp.confirmSetup(userEnteredCode);

// Remove TOTP from account
await auth.totp.delete();
```

---

## Email MFA Management

```ts
await auth.emailMfa.create(); // enable email MFA
await auth.emailMfa.delete(); // disable email MFA
```

---

## Logout

```ts
await auth.logout();             // sign out of current session
await auth.logoutAllSessions();  // sign out of all devices
```

---

## Status Codes

Import `SignInStatus` to compare against sign-in responses:

```ts
import { SignInStatus } from "jobtrk-auth-sdk";

SignInStatus.MFA_REQUIRED   // Email OTP challenge required
SignInStatus.TOTP_REQUIRED  // TOTP challenge required
SignInStatus.MAGIC_LINK     // Magic link sent
SignInStatus.RESET_PASSWORD // Password reset code sent
SignInStatus.SUCCESS        // No MFA — user is signed in
```

---

## Error Handling

All methods throw an `AuthError` on failure:

```ts
import { AuthError } from "jobtrk-auth-sdk";

try {
  await auth.email.signIn({ email, password });
} catch (err) {
  if (err instanceof AuthError) {
    console.error(err.message); // human-readable message
    console.error(err.status);  // HTTP status code
    console.error(err.body);    // raw response body
  }
}
```

---

## React Example

```tsx
import { createAuthClient, SignInStatus, AuthError } from "jobtrk-auth-sdk";
import { useEffect, useState } from "react";

const auth = createAuthClient({ baseUrl: "https://auth.yourapp.com" });

export function useAuth() {
  const [user, setUser] = useState(null);

  // Restore session on mount
  useEffect(() => {
    auth.token.refresh().then(setUser);
  }, []);

  const signIn = async (email: string, password: string) => {
    const result = await auth.email.signIn({ email, password });
    if (!result.status) {
      setUser(auth.token.getUserFromToken());
    }
    return result; // caller handles MFA branching
  };

  const logout = async () => {
    await auth.logout();
    setUser(null);
  };

  return { user, signIn, logout, auth };
}
```