2.3.1 • Published 9 months ago

@identityprovider/servicestack v2.3.1

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

@identityprovider/servicestack

A lightweight wrapper for @identityprovider/client that seamlessly integrates with ServiceStack via its JsonServiceClient.

This SDK is designed to simplify OpenID Connect (OIDC) authentication and token management for applications that already use ServiceStack. It provides a unified client with built-in support for:

✨ Features

  • Authorization Code Flow with PKCE
  • silentAuthorize() via invisible iframe (prompt=none)
  • Secure logout with postLogoutRedirectUri and idTokenHint
  • Session-scoped PKCE values stored in sessionStorage
  • Configurable PKCE cleanup delay (handles React double-render issues)
  • Optional integration with your backend to manage HttpOnly cookie-based tokens
  • Full ID token validation
  • Seamless drop-in for JsonServiceClient-based apps

🚀 Installation

npm install @identityprovider/servicestack

You must also install its peer dependencies:

npm install @identityprovider/client @servicestack/client

🧱 Usage

import { ServiceStackClient } from "@identityprovider/servicestack";

const client = new ServiceStackClient(
    "https://my-app.com",                 // Your app's API base URL
    "https://identity.mycompany.com",     // Your IdP's base URL
    "my-client-id",                       // OIDC client_id
    5000                                  // Optional: PKCE cleanup delay (ms)
);

// Start login
await client.authorize({
    redirectUri: "https://my-app.com/callback",
    scope: "openid profile email"
});

// Silent login if user is already authenticated
const code = await client.silentAuthorize({
    scope: "openid profile email"
});

// Exchange the code for tokens
const tokens = await client.token({
    code,
    redirectUri: "https://my-app.com/callback"
});

// Log out the user
client.logout({
    postLogoutRedirectUri: "https://my-app.com/logout"
});

🔄 PKCE Session Storage

PKCE state, nonce, and code_verifier values are stored in sessionStorage and automatically cleared after a successful token exchange, using a delay (default: 5 seconds) to support React’s double-rendering behavior.

You can customize this delay by passing a fourth argument to the constructor:

const client = new ServiceStackClient(apiUrl, idpUrl, clientId, 7000); // 7 seconds

🔐 HttpOnly Token Flow

If you’re managing tokens via secure HttpOnly cookies (recommended), pass a tokenExchangeHandler to the .token() method:

await client.token({
    code,
    redirectUri: "https://my-app.com/callback",
    tokenExchangeHandler: async (request) => {
        const res = await fetch("/api/token", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(request),
            credentials: "include"
        });

        if (!res.ok) throw new Error("Token exchange failed");

        return await res.json();
    }
});

🛠️ ServiceStack-Specific Features

Because this client extends JsonServiceClient, you can use ServiceStack features like:

client.enableAutoRefreshToken = true;

client.onAuthenticationRequired = async () => {
    await client.authorize({ redirectUri: "https://my-app.com/callback" });
};

client.bearerToken = tokens.accessToken; // If you manage tokens manually
client.refreshTokenUri = "/api/refresh"; // If you use custom refresh endpoint

🧪 Typed Error Handling

This client surfaces all errors from @identityprovider/client, including:

  • StateMismatchError
  • CodeVerifierMissingError
  • NonceMissingError
  • IdTokenMissingError
  • TokenExchangeError
  • SilentAuthorizationError

Handle them with instanceof:

try {
  await client.token();
} catch (e) {
  if (e instanceof TokenExchangeError) {
    console.error("Token error:", e.message);
  }
}

🛡️ Security Best Practices

  • Always use state and nonce (handled automatically)
  • Prefer HttpOnly cookie storage over in-memory access tokens
  • Use SameSite=Lax or Strict for session cookies
  • Avoid storing tokens in localStorage or sharing across tabs

📦 License

MIT

2.3.1

9 months ago

2.3.0

9 months ago

2.2.0

10 months ago

2.1.0

10 months ago

2.0.0

10 months ago

1.0.5

10 months ago

1.0.4

10 months ago

1.0.3

10 months ago

1.0.2

10 months ago

1.0.1

10 months ago

1.0.0

10 months ago