How to
Change user password
Change user passwords securely using Geins Auth Service's signature-based flow
Prerequisites
- Geins account name
- Merchant API key
- Valid credentials (username and password)
Goal
- Change user password securely
- Maintain active session with new Bearer token
- Ensure seamless user experience during password change
Architecture at a glance
- Send username → get signature challenge → send current password + new password with signature → receive new Bearer token
- Session remains active with refreshed authentication
APIs used
- Auth Service:
https://auth-service.geins.io/api/{ACCOUNT_NAME}_prod/password - Merchant API:
https://merchantapi.geins.io/auth/sign/{MERCHANT_API_KEY}
You can find your
ACCOUNT_NAME when you log in to your account. Note that the account name in the auth URL is always followed by _prod.Important: All calls to the auth service must be handled from the server-side to prevent CORS issues. Do not make direct calls to the auth service from client-side code.
Step-by-step
Start password change challenge
Send the user's username to get a signature challenge:
Request example
curl -X POST "https://auth-service.geins.io/api/{ACCOUNT_NAME}_prod/password" \
-H "Content-Type: application/json" \
-d '{
"username": "{USER_EMAIL}"
}'
// Note: This code should run on the server-side to prevent CORS issues
const authUrl = `https://auth-service.geins.io/api/{ACCOUNT_NAME}_prod/password`;
const challengeResponse = await fetch(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ username: '{USER_EMAIL}' })
});
const challengeData = await challengeResponse.json();
Response example
200 OKresponse.json
{
"sign": "IDENTITY_SIGN_STRING"
}
Get signature from Merchant API
Use the signature challenge from step 1 (IDENTITY_SIGN_STRING) to get the signed identity:
Request example
curl -X GET "https://merchantapi.geins.io/auth/sign/{MERCHANT_API_KEY}?identity={IDENTITY_SIGN_STRING}" \
-H "Cache-Control: no-cache"
const params = new URLSearchParams({ identity: 'IDENTITY_SIGN_STRING' });
const signUrl = `https://merchantapi.geins.io/auth/sign/{MERCHANT_API_KEY}?${params}`;
const signResponse = await fetch(signUrl, {
method: 'GET',
cache: 'no-cache'
});
const signature = await signResponse.json();
Response example
200 OKresponse.json
{
"identity": "IDENTITY_SIGN_STRING",
"timestamp": "TIMESTAMP_STRING",
"signature": "SIGNATURE_STRING"
}
Complete password change
Send the signed credentials along with the old and new passwords to complete the password change:
Request example
curl -X POST "https://auth-service.geins.io/api/{ACCOUNT_NAME}_prod/password" \
-H "Content-Type: application/json" \
-d '{
"username": "{USER_EMAIL}",
"password": "{USER_PASSWORD}",
"newPassword": "new-password",
"signature": {
"identity": "IDENTITY_SIGN_STRING",
"timestamp": "TIMESTAMP_STRING",
"signature": "SIGNATURE_STRING"
}
}'
// Note: This code should run on the server-side to prevent CORS issues
const authUrl = `https://auth-service.geins.io/api/{ACCOUNT_NAME}_prod/password`;
const passwordChangeResponse = await fetch(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
username: '{USER_EMAIL}',
password: '{USER_PASSWORD}',
newPassword: 'new-password',
signature: {
identity: "IDENTITY_SIGN_STRING",
timestamp: "TIMESTAMP_STRING",
signature: "SIGNATURE_STRING"
}
})
});
const passwordChangeData = await passwordChangeResponse.json();
Response example
200 OKresponse.json
{
"token": "NEW_JWT_BEARER_TOKEN",
"maxAge": 900
}
Update stored tokens
Clear the old token and save the new one:
# Extract new tokens from response headers during password change
curl -X POST "https://auth-service.geins.io/api/{ACCOUNT_NAME}_prod/password" \
-H "Content-Type: application/json" \
-D headers.txt \
-d '{
"username": "{USER_EMAIL}",
"password": "{USER_PASSWORD}",
"newPassword": "new-password",
"signature": { ... }
}'
# Extract the new refresh token from headers
grep "x-auth-refresh-token" headers.txt
const passwordChangeData = await passwordChangeResponse.json();
if (passwordChangeData.token) {
const newBearerToken = passwordChangeData.token;
// Extract new refresh token from response headers
const newRefreshToken = passwordChangeResponse.headers.get('x-auth-refresh-token');
// Update stored tokens with new values
updateStoredTokens(newBearerToken, newRefreshToken);
}
Security and access
- Always use HTTPS for password change requests
- Validate current password before attempting change
- Old tokens become invalid after successful password change
Common pitfalls
- Not handling the two-step flow properly—both requests to the password endpoint are required
- Forgetting to update stored tokens with new values after password change
Related docs
- Login guide: Log in as user
- Token refresh guide: Refresh user token
- Registration guide: Register user
- Full authentication guide: Authentication flow
Related
Authentication flowChange user passwordGet user ordersLog in userLog out userRefresh user tokenRegister userReset user password