@sinequa/atomic

SharePoint Framework

Routing every request through the host's AadHttpClient, so a web part is authenticated by SharePoint rather than asking for a password.

Inside a SharePoint Framework web part, requests must travel through the host's AadHttpClient — that is what attaches the Azure AD token. A plain fetch leaves without one, the server answers anonymously, and your web part ends up showing a login form in a page the user is already signed into.

Import from the ./spfx subpath, which re-exports everything from the root plus the SharePoint transport.

the optional peer dependency
npm install @microsoft/sp-http --save-peer

Wiring the transport

Two ways, and the second is the one to prefer in new code.

A web part with a Sinequa client
src/webparts/search/SearchWebPart.ts
import { createAtomicClient, createSpfxHttpAdapter } from "@sinequa/atomic/spfx";
import type { AtomicClient } from "@sinequa/atomic";

/**
 * The type the SharePoint SDK provides. Declared here so the example stands alone;
 * in a real web part it comes from `@microsoft/sp-http`.
 */
type AadHttpClientFactoryLike = {
  getClient(resource: string): Promise<never>;
};

export class SearchWebPart {
  private client?: AtomicClient;

  /** Called from the web part's onInit(). */
  async initialize(factory: AadHttpClientFactoryLike, resource: string) {
    const aad = await factory.getClient(resource);

    // Explicit transport: the client routes every request through it, so the
    // Azure AD token is attached and no password is ever asked for.
    this.client = createAtomicClient({
      app: "<your-app>",
      backendUrl: resource,
      httpAdapter: createSpfxHttpAdapter(aad),
    });

    await this.client.initializeConfig();
    await this.client.auth.login();
  }

  search(text: string) {
    if (!this.client) throw new Error("initialize() was not awaited.");

    return this.client.api.query.search({ name: "<your-query>", text, pageSize: 10 });
  }
}

The older, global form

initializeAadHttpClient(aad) registers the client globally, and every free function then routes through it:

the global registration
import { fetchQuery, initializeAadHttpClient } from "@sinequa/atomic/spfx";

// In onInit()
initializeAadHttpClient(await context.aadHttpClientFactory.getClient(resource));

// Anywhere after that
const result = await fetchQuery({ name: "<your-query>", text: "hello" });

// In onDispose()
initializeAadHttpClient(null);

It still works, and a client created without an explicit httpAdapter falls back to it — resolved per request, so a host that registers late is still picked up. Prefer the explicit adapter: it is what a second client targeting another AAD resource needs, and it makes the dependency visible.

What the transport changes

Prop

Type

Pitfalls

What's next

On this page