Authenticating with dddice in Quest Bound

Authenticating with dddice in Quest Bound
🎲
This article is a guest post by Curt, founder of Quest Bound. He recently integrated dddice's 3D dice into Quest Bound, and we asked him to share a post on the process! β€” β™₯ Celeste Bloodreign

If you had to pick one thing that all tabletop RPGs have in common, you'd probably say it's rolling dice. I knew from the beginning that dice rolling mechanics would play a huge part of my app, but deprioritized a nice interface in favor of the more niche features I wanted to bring to the community. When I found out that the fantastically approachable dddice SDK lets you integrate a 3D dice rolling UI with almost no effort, I was instantly sold. Here's a quick overview of my strategy for integrating my app with dddice.

πŸ§ͺ The Use Case

My name's Curt and I'm the creator of a tabletop role-playing game engine called Quest Bound. Quest Bound is an application for creating custom TTRPGs or recreating your favorite ones in a digital format. You could think of it as making your own "D&D Beyond", but for any tabletop RPG. Once your ruleset and custom, automated character sheets are created, you can make a character and bring it to the table or virtual tabletop.

That, of course, means rolling dice. From anywhere within Quest Bound, users may open a dice panel, select any number of dice and roll. Quest Bound will provide the UI for dice selection, authentication and switching between rooms--all wrappers around the dddice API. The dddice SDK will provide the 3D rolling animations and real time connection to sync rolls between platforms.

🎲 Rolling without Friction

One of the (many) advantages of using dddice is giving users the ability to sync rolls between platforms. This is crucial for integrating Quest Bound with virtual tabletops, but I also wanted to lower the friction to rolling as much as possible. Quest Bound is often used as a platform for solo play, so needing to authenticate with the online dice roller would be a non-starter.

Fortunately, the dddice API has an endpoint for creating a guest user that requires no authentication. Guest users can roll, create and join rooms, giving Quest Bound all the functionality it needs without requiring users to login. Perfect!

Of course, users should have the option of authenticating with their dddice account as well. Authenticated users can choose 3D dice from their Digital Dice Box and select from their existing rooms.

Here's the plan – Quest Bound users who login for the first time will have a dddice guest user created on their behalf, which will be used to roll. At anytime, they can authenticate with their dddice account to select a room and choose a theme from their Digital Dice Box.

βš’ Working with the dddice SDK

The SDK is a pleasure to use. Instantiating it requires only a ref to a canvas element and the user auth token. I made a custom hook, useDice, that took the canvas ref as an argument. The rest of the authentication logic is held within the hook.

That logic mostly boiled down to two functions, plus a few helpers to wrap the API endpoints.

export const authenticateDddiceUser = async (): Promise<DiceUser> => {
  // These are pulled from Cookies
  const authUserToken = getToken();
  const guestUserToken = getGuestToken();

  const token = authUserToken ?? guestUserToken;
  const isGuest = !authUserToken;

  if (token) {
    const user = await getUser(token);
    const { roomSlug, roomName, roomPasscode, rooms } = await getLastRoom(token, isGuest);
    return {
      roomSlug,
      roomName,
      roomPasscode,
      userToken: token,
      username: user.data.username,
      userId: user.data.uuid,
      rooms: !isGuest ? rooms : [],
      isGuest,
    };
  }

  const res = await bootstrapGuestUser();
  return res;
};

const bootstrapGuestUser = async () => {
  const userToken = await createGuestUser();
  setGuestToken(userToken);

  const { slug, name } = await createRoom(userToken);
  // This slug is used in the getLastRoom function
  localStorage.setItem('dddice-guest-room', slug);

  const guestUser = await getUser(userToken);

  return {
    roomSlug: slug,
    roomName: name,
    userToken,
    userId: guestUser.data.uuid,
    username: guestUser.data.username,
    rooms: [],
    isGuest: true,
  };
};
πŸ’‘
Quick tip! The creatGuestUser call will accept an auth header. If you provide one, it will be used to enforce the rate limit of 3 calls per minute. During this initial set up, I provided this call with the Quest Bound API key, which spread that rate limit across all QB users 😬

Just like that, 3D dice rolling across Quest Bound!

πŸ”‘ Third Party Authentication

When it comes time for users to login to their dddice account, you can follow the third party auth flow. All you have to do is create an activation code, then poll for that code's usage. Once the user accepts the code in another tab, you can retrieve their token from the readActivationCode endpoint.

Create a new instance of the SDK with the new token and be sure to provide it within the authorization header of the dddice API calls.

πŸš€ Conclusion

Working with the dddice SDK was a great experience. Within a couple of hours, Quest Bound had a robust dice rolling mechanism with 3D elements, authentication and real time syncing between platforms. I'm looking forward to following the latest dddice features and continuing to build out this integration.


This is a guest post written by Curt, the founder of Quest Bound. You can sign up for Early Access, or follow Quest Bound's development on their blog, insta or join their discord!