This is an enterprise-only feature. Please contact us in slack or via email (hello@dynamic.xyz) to enable.

Introduction

If you have built your own authentication system or use other auth providers outside Dynamic, you may want to keep using those services while taking advantage of Dynamic’s product to enable web3-based functionality and interactions.

Third-party authentication allows you to do this by exchanging your token from a JWT issuer to “sign-in” or “link” to Dynamic.

Approach

Dynamic provides a new API endpoint and utility hook useExternalAuth, to allow sign-in or linking with an external 3rd party JWT by exchanging it for a Dynamic JWT. This will return Dynamic’s standard sign-in artifacts (ie, minified JWT and user).

At a high level, this will do the following steps:

  1. Verify the authenticity of the JWT by getting the public key from a JWKS endpoint provided by you, and using this public key to verify the JWT.
  2. Require you to provide exact value for either the iss (issuer) JWT claim. If the value of this field deviates from that is provided in the project environment’s configuration, we will reject the JWT.
  3. Dynamic will also require the sub (subject, or user ID) field be provided. These will correspond to the your user ID. These will be mapped to the similar user model in Dynamic.
  4. Dynamic will also require exp (expires at) JWT claim from external JWT. Dynamic will ensure that this exp claim is respected with timeouts on the SDK.
  5. Once signed in using this external JWT, we will create an new verified credential of type externalAuth, letting us know that the user has an external authentication mechanism they used to verify their account. This should have externalUserId with the value of the JWT’s sub.
  6. Optional verified credential data, such as e-mail sign in can be provided as part of the JWT. This would allow Dynamic to create an email verified credential tied to the Dynamic user on our side.

Workflow

Dashboard Configuration

To access this page, navigate to the Third-Party Auth page in your dashboard.

  1. Provide values for the following fields:
    • iss (required): Standard JWT claim for the “issuer” of the JWT. This should be the entity that issued the token. This is typically a URL, but can be a valid constant string.
    • jwksUrl (required): This is a publicly-accessible URL that returns the JWT’s signer public key in the standard JWKS format. This is used to verify the signatures of your JWTs.
    • aud (optional): Standard JWT claim for the “audience” of the JWT. This should be the intended recipient of the token. This is typically a URL, but can be a valid constant string.
    • cookieName (optional): For clients that use cookie-based authentication for their 3rd party auth and who have no acccess to the raw JWT on the frontend, we provide a way for clients to specify the cookie name to expect the JWT to be stored.
  2. When you are ready, enable the feature using the toggle.
  3. Additionally, we provide a way for you to check a JWT against your saved settings, and we will return the errors, if any.

Frontend Implementation

After properly configuring the settings for this feature, you should be able to “sign-in” with a non-Dynamic JWT token by calling the signInWithExternalJwt method from the useExternalAuth hook.

const { signInWithExternalJwt } = useExternalAuth();

try {
  // `externalUserId`: User ID in the external auth system
  // `externalJwt`: Raw encoded JWT issued by external auth system
  const userProfile = await signInWithExternalJwt({
    externalUserId,
    externalJwt
  });

  if (userProfile) {
    // You should be logged in at this point
  }
} catch (e: any) {
  console.error('Dynamic login failed:', e);
}

Similarly, you can verify the user using the verifyWithExternalJwt method:

const { verifyWithExternalJwt } = useExternalAuth();

try {
  const verifiedProfile = await verifyWithExternalJwt({
    externalUserId,
    externalJwt
  });

  if (verifiedProfile) {
    // User verification successful
  }
} catch (e: any) {
  console.error('Dynamic verification failed:', e);
}