Skip to main content

Auto-Create a Developer License

Provision Licenses Programmatically

The previous section covers creating a single Developer License for yourself in the Console. That works well if your app operates under one shared license.

Some apps need a new Developer License per end user instead — for example, a multi-tenant app where each customer brings and manages their own API key rather than sharing yours. For that pattern, the Login with DIMO SDK can mint (or reconnect) a Developer License directly from your app's onboarding flow, without sending anyone to the Console.

Developer Notes

Provisioning still creates a real, on-chain Developer License — it's the same object you'd otherwise create manually. The SDK just automates account creation, on-chain registration, and key generation on behalf of whoever is onboarding into your app.

When to Use This

Reach for provisioning when your app's architecture requires one Developer License per tenant or end user, so each of them supplies their own API key rather than all traffic flowing through a single shared license.

How It Works

1

Initialize the SDK

Initialize the SDK once at app startup with your own clientId and redirectUri — these must already be registered in the Developer Console before provisioning will work. This is the identity of your app, not the license being provisioned.

import { initializeDimoSDK } from '@dimo-network/login-with-dimo';

initializeDimoSDK({
clientId: process.env.REACT_APP_DIMO_CLIENT_ID!,
redirectUri: process.env.REACT_APP_DIMO_REDIRECT_URI!,
environment: 'production',
});
2

Trigger Provisioning

Render the provisioning component (React) or open the provisioning URL directly (any other stack) during your onboarding flow.

import {
DimoSDKModes,
ProvisionDeveloperLicenseWithDimo,
} from '@dimo-network/login-with-dimo';
import type { ProvisionResult } from '@dimo-network/login-with-dimo';

function OnboardingPage() {
const handleSuccess = async (result: ProvisionResult) => {
// Persist the credentials — warn the user to save the key now;
// it cannot be retrieved again after this point.
await myApi.saveTenantCredentials({
clientId: result.clientId,
apiKey: result.privateKey, // raw hex, ready to use
});

navigate('/dashboard');
};

return (
<ProvisionDeveloperLicenseWithDimo
mode={DimoSDKModes.POPUP}
domain="https://yourapp.com"
onSuccess={handleSuccess}
onError={(err) => console.error('Provision failed', err)}
/>
);
}
PropTypeRequiredDescription
modeDimoSDKModesyesPOPUP or REDIRECT
domainstringyesYour app's origin URL — recorded on the developer license NFT. Use your canonical origin, not localhost.
onSuccess(result: ProvisionResult) => voidyesCalled with credentials when provisioning completes
onError(error: Error) => voidyesCalled on any failure
existingTokenIdnumbernoToken ID of a license to reconnect (skip mint)
existingClientIdstringnoClient ID of a license to reconnect (skip mint)
3

Handle the Result

Both approaches deliver the same shape once provisioning succeeds:

interface ProvisionResult {
clientId: string; // DIMO client ID (0x-prefixed address)
privateKey: string; // raw hex private key — no 0x prefix
domain: string; // the domain you passed in, echoed back
tokenId: number; // on-chain token ID of the new developer license NFT
}
Terminology

The Console UI calls this secret an API Key; the provisioning response calls the same value privateKey. They're the same secret — just named differently depending on which flow created it.

Store privateKey encrypted at rest immediately. Once the popup or redirect closes, DIMO cannot show it to you again — the same one-time-display rule as API keys generated manually in the Console.

4

Reconnect an Existing License (optional)

If a user already has a license from a previous session (e.g. they're switching devices or re-authorizing), pass their existing tokenId and clientId to skip minting a new one:

<ProvisionDeveloperLicenseWithDimo
mode={DimoSDKModes.POPUP}
domain="https://yourapp.com"
onSuccess={handleSuccess}
onError={handleError}
existingTokenId={user.licenseTokenId}
existingClientId={user.clientId}
/>

For the manual URL approach, pass the same values as additional query parameters on the provisioning URL.

How the Flow Works

[ Your App ]
└── triggers provisioning (component click, or window.open)

login.dimo.org (entryState=PROVISION_DEVELOPER_LICENSE)
└── authenticates the user
└── creates or reconnects a developer license NFT
└── generates a private key for the license

popup/redirect posts { eventType: "provisionResponse", clientId, tokenId, privateKey }

[ Your App ]
└── validates the origin, reads the result
└── stores credentials, continues onboarding

Security Notes

  • The private key is generated inside the DIMO popup/redirect and delivered only via postMessage with strict origin validation — it never touches your server during provisioning.
  • Store it encrypted at rest. Once the flow completes it cannot be retrieved from DIMO again.
  • The domain you provide is recorded on-chain against the license NFT — use your app's real origin.

Client SDK: DIMO Connect