An OSDK Login example for NextJS

The boilerplate in platform documentation for OSDK apps is missing an example of a basic login flow that will work in NextJS apps. I have seen a NextJS example out there in Palantir’s open source projects, but I could not find it. The last time I saw the example though it was for an SPA. Many React apps today use NextJS for its server capabilities. So, I created a boilerplate example that works.

import { Client, createClient, Osdk } from '@osdk/client';
import { createPublicOauthClient } from '@osdk/oauth';
import { useCallback, useEffect, useState } from 'react';
import { User, Users } from '@osdk/foundry.admin';

// setup the OSDK
const clientId = process.env['NEXT_PUBLIC_OSDK_CLIENT_ID'];
const url = process.env['NEXT_PUBLIC_FOUNDRY_STACK_URL'];
const ontologyRid = process.env['NEXT_PUBLIC_ONTOLOGY_RID'];
const redirectUrl = window.location.href.split('?')[0].replace(/\/+$/, '');
const scopes: string[] = [
  'api:use-ontologies-read',
  'api:use-ontologies-write',
  'api:use-admin-read',
  'api:use-connectivity-read',
  'api:use-connectivity-execute',
  'api:use-mediasets-read',
  'api:use-mediasets-write',
];

const auth = createPublicOauthClient(
  clientId!,
  url!,
  redirectUrl,
  true,
  undefined,
  window.location.toString(),
  scopes,
);
const client: Client = createClient(url!, ontologyRid!, auth);

export default function App() {
  const [user, setUser] = useState<User | null>(null);

  const singOut = useCallback(async () => {
    await auth.signOut();
    window.location.reload();
  }, [auth]);

  const singIn = useCallback(async () => {
    try {
      await auth.signIn();
    } catch (error) {
      console.error('Sign-in error:', error);
    }
  }, [auth]);

  const getUserDetails = useCallback(async () => {
    try {
      const user: User = await Users.getCurrent(client);
      setUser(user);
      console.log('Current User:', user);
    } catch (error) {
      console.error('Error fetching user details:', error);
    }
  }, []);

  useEffect(() => {
    getUserDetails();
  }, [getUserDetails]);
  return (
    <div>
      {user ? (
        <>
          <p>Current logged in user: {user.email}</p>
          <button onClick={singOut}>Sign Out</button>
        </>
      ) : (
        <>
          <p>Welcome! Please sign in to continue.</p>
          <button onClick={singIn}>Sign In</button>
        </>
      )}
    </div>
  );
}

IMPORTANT: to make this work without putting use client all over the place and dealing with window is undefined errors use a dynamic import. Let’s assume the code above is in JibDashboard. To use do:

'use client';

import dynamic from 'next/dynamic';

// important, OSDK is client side only! This prevents use client all over the place
// and ensures we don't get window undefined errors and the like
const JibDashboard = dynamic(() => import('./JibDashboard'), { ssr: false });

export default function JibClient() {
  return <JibDashboard />;
}

It would be great to have a first class login example so users can customize login/logout. This is the most common thing developers need to do in OSDK apps IMO.

1 Like