The IBEX API v1.2 introduces flexible user creation options that go beyond the traditional passkey-only approach. You can now create user accounts in four different ways, depending on your application's needs:
All user creation scenarios use the GET /v1.2/auth/sign-up endpoint, with different query parameters to control the behavior:
passkeys: Set to FALSE to skip passkey creation, or TRUE (default) to require passkeyemail: Optional email address for validationUse case: Quick account creation for users who want immediate access without biometric authentication or email verification.
Endpoint: GET /v1.2/auth/sign-up?passkeys=FALSE
Request Example:
GET /v1.2/auth/sign-up?passkeys=FALSE
Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"issuer": "foo.domain",
"audience": "foo.domain",
"subject": "<externalUserId>",
"roles": ["USER"],
"userId": "<userId>",
"externalUserId": "<externalUserId>",
"emailValidationRequired": false,
"authMethod": "EXTERNAL_USER_ID",
"hasPasskey": false
}
access_token: JWT for API authentication (duration: ~1h)refresh_token: JWT to refresh access token (store securely)subject (externalUserId): Unique user identifier for this rpIduserId: Internal user IDNext steps: The user can immediately use the API with the provided tokens. A passkey can be added later using POST /v1.2/auth/sign-up with the externalUserId.
Use case: Create an account with email verification for security, but defer wallet creation to a later step.
Step 1: Request Sign Up with Email
Endpoint: GET /v1.2/auth/sign-up?passkeys=FALSE&email=user@example.com
Request Example:
GET /v1.2/auth/sign-up?passkeys=FALSE&email=user@example.com
Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"issuer": "foo.domain",
"audience": "foo.domain",
"subject": "<externalUserId>",
"roles": ["USER"],
"userId": "<userId>",
"externalUserId": "<externalUserId>",
"emailValidationRequired": true,
"authMethod": "EMAIL",
"hasPasskey": false
}
user@example.com. The user must validate their email in the next step.
Step 2: Validate Email
Endpoint: POST /v1.2/auth/sign-up
Request Example:
POST /v1.2/auth/sign-up
Content-Type: application/json
{
"emailCode": "123456",
"externalUserId": "<externalUserId-from-step-1>"
}
Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"issuer": "foo.domain",
"audience": "foo.domain",
"subject": "<externalUserId>",
"roles": ["USER"],
"emailValidationStatus": "validated",
"authMethod": "EMAIL",
"hasPasskey": false
}
access_token and refresh_token: JWT tokens for API accesssubject (externalUserId): Unique user identifieremailValidationStatus: Confirms email is validatedNext steps: The user account is created and email-validated. A passkey (wallet) can be added later using POST /v1.2/auth/sign-up with the externalUserId and a credential.
Use case: Maximum security: create an account with both biometric authentication (passkey) and email verification, deploying a wallet immediately.
Step 1: Request Sign Up with Passkey and Email
Endpoint: GET /v1.2/auth/sign-up?email=user@example.com (passkeys=TRUE is default)
Request Example:
GET /v1.2/auth/sign-up?email=user@example.com&user.name=user@example.com&user.displayname=John%20Doe
Response (200 OK):
{
"credentialRequestOptions": {
"rp": { "id": "foo.domain", "name": "foo.domain" },
"user": {
"id": "<base64url>",
"name": "foo.domain <shortId>",
"displayName": "foo.domain <shortId>"
},
"challenge": "<base64url>",
"pubKeyCredParams": [{ "alg": -7, "type": "public-key" }],
"authenticatorSelection": {
"residentKey": "preferred",
"userVerification": "preferred"
},
"attestation": "none",
"timeout": 60000
},
"emailValidationRequired": true
}
user@example.com. The email code is optional in the next step (account will be created even if code is invalid, with a warning).
Step 2: Complete Sign Up with Passkey (and optionally Email Code)
Endpoint: POST /v1.2/auth/sign-up
Request Example (with email code):
POST /v1.2/auth/sign-up
Content-Type: application/json
{
"credential": {
"id": "AVZs0qRCBSmfThZWu37g...",
"rawId": "AVZs0qRCBSmfThZWu37g...",
"type": "public-key",
"response": {
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVh...",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoi..."
}
},
"emailCode": "123456",
"chainIds": [421614]
}
Request Example (without email code - still works):
POST /v1.2/auth/sign-up
Content-Type: application/json
{
"credential": {
"id": "AVZs0qRCBSmfThZWu37g...",
"rawId": "AVZs0qRCBSmfThZWu37g...",
"type": "public-key",
"response": {
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVh...",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoi..."
}
},
"chainIds": [421614]
}
Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"issuer": "foo.domain",
"audience": "foo.domain",
"subject": "<externalUserId>",
"roles": ["USER"],
"safeAddress": {
"421614": "0xd676c6188195372EC269E9C2cAf815C56436A679"
},
"chainId": 421614,
"emailValidationStatus": "validated",
"authMethod": "PASSKEY_AND_EMAIL",
"hasPasskey": true
}
access_token and refresh_token: JWT tokenssubject (externalUserId): Unique user identifiersafeAddress: Deployed Safe wallet addresses by chainIdemailValidationStatus: Email validation status (if code was provided)Use case: Traditional v1/v1.1 behavior: create an account with passkey and deploy wallet immediately, without email verification.
Step 1: Request Sign Up with Passkey
Endpoint: GET /v1.2/auth/sign-up (passkeys=TRUE is default, no email parameter)
Request Example:
GET /v1.2/auth/sign-up?user.name=user@example.com&user.displayname=John%20Doe
Response (200 OK):
{
"credentialRequestOptions": {
"rp": { "id": "foo.domain", "name": "foo.domain" },
"user": {
"id": "<base64url>",
"name": "foo.domain <shortId>",
"displayName": "foo.domain <shortId>"
},
"challenge": "<base64url>",
"pubKeyCredParams": [{ "alg": -7, "type": "public-key" }],
"authenticatorSelection": {
"residentKey": "preferred",
"userVerification": "preferred"
},
"attestation": "none",
"timeout": 60000
},
"emailValidationRequired": false
}
Step 2: Complete Sign Up with Passkey
Endpoint: POST /v1.2/auth/sign-up
Request Example:
POST /v1.2/auth/sign-up
Content-Type: application/json
{
"credential": {
"id": "AVZs0qRCBSmfThZWu37g...",
"rawId": "AVZs0qRCBSmfThZWu37g...",
"type": "public-key",
"response": {
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVh...",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoi..."
}
},
"chainIds": [421614]
}
Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"issuer": "foo.domain",
"audience": "foo.domain",
"subject": "<externalUserId>",
"roles": ["USER"],
"safeAddress": {
"421614": "0xd676c6188195372EC269E9C2cAf815C56436A679"
},
"chainId": 421614,
"authMethod": "PASSKEY",
"hasPasskey": true
}
access_token and refresh_token: JWT tokenssubject (externalUserId): Unique user identifiersafeAddress: Deployed Safe wallet addresses by chainIdThe v1.2 API provides flexible user creation options:
| Scenario | Parameters | Result |
|---|---|---|
| a) Simple Session | passkeys=FALSE |
JWT tokens immediately, no wallet |
| b) Email-Validated Account | passkeys=FALSE&email=... |
JWT tokens + email validation, no wallet |
| c) Wallet + Email | email=... (passkeys=TRUE default) |
Wallet deployed + email validation |
| d) Wallet Only | No parameters (default) | Wallet deployed, no email |
POST /v1.2/auth/sign-up with the externalUserId and a credential.
For complete API documentation, see: