Skip to main content

Login with OTP

The loginWithOtp method authenticates existing players using a one-time password (OTP) sent to their email or phone number. This is used after generating an OTP.

Prerequisites

Before calling loginWithOtp, you must:

  1. Generate an OTP using genOtp
  2. Player must have received the OTP via email/SMS
  3. Player must enter the OTP in your game

Basic Usage

Login with either email or phone number and the OTP.

Email Login

MoitribeSDK('my-game-id', 'loginWithOtp', {
emailid: 'player@example.com',
otp: '123456',
callback: (result) => {
if (result.success) {
console.log('Login successful');
startGame();
} else {
console.error('Login failed:', result.msg);
}
}
});

Phone Login

MoitribeSDK('my-game-id', 'loginWithOtp', {
phno: '+1234567890',
otp: '123456',
callback: (result) => {
if (result.success) {
console.log('Login successful');
startGame();
} else {
console.error('Login failed:', result.msg);
}
}
});

Parameters

ParameterTypeRequiredDescription
emailidstringEither email or phonePlayer's email address
phnostringEither email or phonePlayer's phone number (E.164 format)
otpstringYes6-digit OTP code
callbackfunctionYesCalled with login result
warning

You must provide either emailid or phno (matching what was used in genOtp), plus the otp code. Omitting required fields returns an error.

Response Format

The callback receives:

{
success: boolean; // true if login succeeded
msg?: string; // Error message (if failed)
statuscode?: number; // Error code (if failed)
}

Success Response

{
success: true
}

After successful login, the SDK's loginCallback (from initialization) is automatically called with player data.

Error Response

{
success: false,
msg: 'Invalid OTP',
statuscode: 102
}

Common Status Codes

CodeMeaningAction
0SuccessPlayer logged in
102Invalid OTPAsk player to re-enter OTP
104OTP expiredGenerate new OTP
106Account not foundUse createWithOtp instead

Complete Login Flow

Here's a complete email/OTP login flow:

const GAME_ID = 'my-game-id';

// Step 1: Player enters email
function showEmailLogin() {
const email = prompt('Enter your email:');

if (!email || !isValidEmail(email)) {
alert('Please enter a valid email');
return;
}

requestOtp(email);
}

// Step 2: Generate OTP
function requestOtp(emailid) {
showLoading('Sending verification code...');

MoitribeSDK(GAME_ID, 'genOtp', {
emailid: emailid,
callback: (result) => {
hideLoading();

if (result.success) {
showOtpInput(emailid);
} else {
alert('Failed to send code: ' + result.msg);
}
}
});
}

// Step 3: Player enters OTP
function showOtpInput(emailid) {
const otp = prompt(`Enter the 6-digit code sent to ${emailid}:`);

if (!otp || otp.length !== 6) {
alert('Please enter a valid 6-digit code');
showOtpInput(emailid); // Try again
return;
}

loginWithOtp(emailid, otp);
}

// Step 4: Verify OTP and login
function loginWithOtp(emailid, otp) {
showLoading('Verifying code...');

MoitribeSDK(GAME_ID, 'loginWithOtp', {
emailid: emailid,
otp: otp,
callback: (result) => {
hideLoading();

if (result.success) {
console.log('Login successful!');
// SDK automatically calls loginCallback with player data
} else {
handleLoginError(result, emailid);
}
}
});
}

// Step 5: Handle errors
function handleLoginError(result, emailid) {
if (result.statuscode === 102) {
alert('Invalid code. Please try again.');
showOtpInput(emailid); // Let player retry
} else if (result.statuscode === 104) {
alert('Code expired. Requesting a new one...');
requestOtp(emailid); // Generate new OTP
} else if (result.statuscode === 106) {
alert('Account not found. Please create an account.');
// Redirect to account creation
showCreateAccount(emailid);
} else {
alert('Login failed: ' + (result.msg || 'Unknown error'));
}
}

function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

Receiving Player Data

After successful login, the SDK automatically calls the loginCallback defined during initialization:

MoitribeSDK('my-game-id', 'init', {
loginCallback: (result) => {
if (result.success) {
// This is called after successful loginWithOtp
const player = result.playerdata;

console.log('Player logged in:', player.name);
console.log('Player ID:', player.id);
console.log('Email:', player.emailid);

// Start game with player data
startGame(player);
}
}
});

TypeScript Example

import MoitribeSDK from '@veniso/moitribe-js';

interface LoginResult {
success: boolean;
msg?: string;
statuscode?: number;
}

interface LoginParams {
emailid?: string;
phno?: string;
otp: string;
callback: (result: LoginResult) => void;
}

const GAME_ID = 'my-game-id';

function loginWithEmailOtp(email: string, otp: string): void {
const params: LoginParams = {
emailid: email,
otp: otp,
callback: (result: LoginResult) => {
if (result.success) {
console.log('Login successful');
// SDK loginCallback will be called with player data
} else {
handleLoginError(result, email);
}
}
};

MoitribeSDK(GAME_ID, 'loginWithOtp', params);
}

function handleLoginError(result: LoginResult, email: string): void {
switch (result.statuscode) {
case 102:
showError('Invalid OTP. Please try again.');
break;
case 104:
showError('OTP expired. Please request a new one.');
break;
case 106:
showError('Account not found. Please create an account.');
navigateToCreateAccount(email);
break;
default:
showError(result.msg || 'Login failed. Please try again.');
}
}

OTP Input Validation

Validate OTP format before submitting:

function isValidOtp(otp) {
// Check if 6 digits
return /^\d{6}$/.test(otp);
}

function handleOtpSubmit(emailid, otp) {
// Remove any spaces or hyphens
const cleanedOtp = otp.replace(/[\s-]/g, '');

if (!isValidOtp(cleanedOtp)) {
showError('Please enter a valid 6-digit code');
return;
}

MoitribeSDK('my-game-id', 'loginWithOtp', {
emailid: emailid,
otp: cleanedOtp,
callback: handleLoginResult
});
}

Auto-Submit OTP

Automatically submit when player enters 6 digits:

function showOtpInputForm(emailid) {
const input = document.getElementById('otp-input');

input.addEventListener('input', (e) => {
const otp = e.target.value;

// Auto-submit when 6 digits entered
if (otp.length === 6 && isValidOtp(otp)) {
submitOtp(emailid, otp);
}
});
}

function submitOtp(emailid, otp) {
showLoading('Verifying...');

MoitribeSDK('my-game-id', 'loginWithOtp', {
emailid: emailid,
otp: otp,
callback: (result) => {
hideLoading();

if (result.success) {
console.log('Login successful');
} else {
showError(result.msg || 'Invalid code');
clearOtpInput();
}
}
});
}

Resend OTP

Allow players to request a new OTP:

function showOtpInputWithResend(emailid) {
let canResend = false;
let resendTimer = 30; // 30 second cooldown

// Start cooldown timer
const interval = setInterval(() => {
resendTimer--;
updateResendButton(`Resend in ${resendTimer}s`);

if (resendTimer <= 0) {
clearInterval(interval);
canResend = true;
updateResendButton('Resend Code');
}
}, 1000);

// Handle resend click
document.getElementById('resend-btn').onclick = () => {
if (canResend) {
resendOtp(emailid);
}
};
}

function resendOtp(emailid) {
MoitribeSDK('my-game-id', 'genOtp', {
emailid: emailid,
callback: (result) => {
if (result.success) {
showMessage('New code sent!');
} else {
showError('Failed to send new code');
}
}
});
}

Handling "Account Not Found"

If the OTP is valid but no account exists, redirect to account creation:

MoitribeSDK('my-game-id', 'loginWithOtp', {
emailid: 'newplayer@example.com',
otp: '123456',
callback: (result) => {
if (result.success) {
console.log('Login successful');
} else if (result.statuscode === 106) {
// Account doesn't exist - offer to create one
showDialog({
title: 'Account Not Found',
message: 'Would you like to create an account?',
buttons: [
{
text: 'Create Account',
action: () => {
// OTP is still valid - use it for account creation
createAccountWithOtp('newplayer@example.com', '123456');
}
},
{
text: 'Cancel',
action: () => showEmailLogin()
}
]
});
}
}
});

Best Practices

1. Clear Error Messages

Provide helpful feedback for each error type:

function getErrorMessage(statuscode) {
const messages = {
102: 'The code you entered is incorrect. Please try again.',
104: 'This code has expired. Please request a new one.',
106: 'No account found with this email. Please create an account.',
};

return messages[statuscode] || 'Login failed. Please try again.';
}

2. OTP Expiration Warning

Warn players that OTPs expire:

MoitribeSDK('my-game-id', 'genOtp', {
emailid: email,
callback: (result) => {
if (result.success) {
showMessage(
'Code Sent',
'A 6-digit code was sent to your email. It will expire in 10 minutes.'
);
}
}
});

3. Rate Limiting

Track failed attempts and implement delays:

let failedAttempts = 0;

MoitribeSDK('my-game-id', 'loginWithOtp', {
emailid: email,
otp: otp,
callback: (result) => {
if (result.success) {
failedAttempts = 0;
} else {
failedAttempts++;

if (failedAttempts >= 3) {
showError('Too many failed attempts. Please wait 1 minute.');
setTimeout(() => {
failedAttempts = 0;
}, 60000);
}
}
}
});
tip

OTPs are typically valid for 10-15 minutes. If a player needs more time, implement a "Resend Code" button to generate a fresh OTP.

Next Steps

After successful login:

Related authentication topics: