Use IDKit sessions when you want to link user actions over time. Unlike
IDKit.request flows used for one-time actions, sessions return a
session_id that you can save and reuse in later interactions.
Step 1: Generate an RP signature (backend only)
Sessions still require signed rp_context, generated server-side.
import { signRequest } from "@worldcoin/idkit-core/signing" ;
export async function POST () : Promise < Response > {
const signingKey = process . env . RP_SIGNING_KEY ;
if ( ! signingKey ) {
return Response . json ({ error: "Missing RP_SIGNING_KEY" }, { status: 500 });
}
const { sig , nonce , createdAt , expiresAt } = signRequest (
"session-auth" ,
signingKey ,
);
return Response . json ({
sig ,
nonce ,
created_at: createdAt ,
expires_at: expiresAt ,
});
}
Never generate RP signatures on the client and never expose your RP signing
key. If the key leaks, attackers can forge requests as your app.
Step 2: Create or prove the session in your client
createSession: first-time user, no saved session_id.
proveSession: returning user with existing session_id.
JavaScript
React
Swift
Kotlin
import { IDKit , CredentialRequest } from "@worldcoin/idkit-core" ;
const rpSig = await fetch ( "/api/rp-signature" , {
method: "POST" ,
}). then (( r ) => r . json ());
const sessionConfig = {
app_id: "app_xxxxx" ,
rp_context: {
rp_id: "rp_xxxxx" ,
nonce: rpSig . nonce ,
created_at: rpSig . created_at ,
expires_at: rpSig . expires_at ,
signature: rpSig . sig ,
},
environment: "production" ,
};
const orbCredential = CredentialRequest ( "orb" );
const builder = existingSessionId
? IDKit . proveSession ( existingSessionId , sessionConfig )
: IDKit . createSession ( sessionConfig );
const request = await builder . constraints ( orbCredential );
const connectUrl = request . connectorURI ;
const completion = await request . pollUntilCompletion ();
if ( completion . success ) {
const sessionId = completion . result . session_id ;
const sessionNullifier = completion . result . responses [ 0 ]?. session_nullifier ;
// Persist sessionId for future proveSession() calls.
}
Step 3: Verify the proof in your backend and persist session_id
After successful completion, send the returned payload to your backend and
forward it directly to: POST https://developer.world.org/api/v4/verify/{rp_id}.
app . post ( "/api/verify-session" , async ( req , res ) => {
const { rp_id , devPortalPayload } = req . body ;
const response = await fetch (
`https://developer.world.org/api/v4/verify/ ${ rp_id } ` ,
{
method: "POST" ,
headers: { "content-type" : "application/json" },
body: JSON . stringify ( devPortalPayload ),
},
);
const payload = await response . json ();
if ( response . ok && devPortalPayload . session_id ) {
await saveUserSessionId ( req . user . id , devPortalPayload . session_id );
}
res . status ( response . ok ? 200 : response . status ). json ( payload );
});
On first success, save session_id to your user record. On later flows, load
it and call proveSession.