Login with Paysera
Paysera offers a secure API that lets your customers sign in to your website using their Paysera account. Quick, fast, and convenient way for people to log into your website.
This use case implements OAuth 2.0 authorization code flow for secure user authentication.
Use Cases
Registration: Let people quickly create an account without setting a password or filling registration forms. Obtain user data confirmed by Paysera system.
Login: Let people sign in with the same data they use in Paysera. No need to save user data in your system.
Benefits
- ✅ Real Identity - When people log in with Paysera, they share their real identity - name, gender, locale, phone
- ✅ Automatic Updates - Get up-to-date customer data from Paysera, which is renewed automatically
- ✅ Permission Control - Allow users to control what info they share
OAuth Flow
Integration Steps
Step 1: Redirect to Authorization
Redirect user to: https://www.paysera.com/frontend/oauth
Required parameters: response_type=code, client_id, redirect_uri, scope
Example URL:
https://www.paysera.com/frontend/oauth?
response_type=code&
client_id=wkVd93h2uS&
redirect_uri=https://yoursite.com/callback&
scope=email+name&
state=random_string
Step 2: Handle Callback
User is redirected back with authorization code:
https://yoursite.com/callback?code=AUTHORIZATION_CODE&state=random_string
Step 3: Exchange Code for Token
Make POST request to: https://wallet.paysera.com/oauth/v1/token
Step 4: Get User Information
Use access token: GET https://wallet.paysera.com/rest/v1/user/me
Implementation Examples
- PHP
- JavaScript
- Python
<?php
require_once 'vendor/autoload.php';
use Paysera\WalletApi\ClientFactory;
use Paysera\WalletApi\OAuth\Consumer;
session_start();
// Configuration
$clientId = 'wkVd93h2uS';
$secret = 'IrdTc8uQodU7PRpLzzLTW6wqZAO6tAMU';
// Create API client
$api = ClientFactory::create([
'auth' => [
'mac' => [
'mac_id' => $clientId,
'mac_secret' => $secret,
],
],
]);
$oauth = $api->oauthConsumer();
try {
// Check if we have token
if (!isset($_SESSION['token'])) {
// Try to get token from callback
$token = $oauth->getOAuthAccessToken();
if ($token === null) {
// No token yet, redirect to authorization
$scopes = [
Consumer::SCOPE_EMAIL,
Consumer::SCOPE_PHONE,
Consumer::SCOPE_FULL_NAME,
];
$authUrl = $oauth->getAuthorizationUri($scopes, null);
header('Location: ' . $authUrl);
exit;
} else {
// Got token from callback
$_SESSION['token'] = $token;
}
}
// We have token, get user info
if (isset($_SESSION['token'])) {
$client = $api->walletClientWithToken($_SESSION['token']);
$user = $client->getUser();
// User data
$userId = $user->getId();
$email = $user->getEmail();
$name = $user->getDisplayName();
$phone = $user->getPhone();
// Update token (might be refreshed)
$_SESSION['token'] = $client->getCurrentAccessToken();
// Use user data for login/registration
echo "Welcome, $name!";
echo "<br>Email: $email";
echo "<br>User ID: $userId";
}
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
}
HTML + JavaScript
<!DOCTYPE html>
<html>
<head>
<title>Login with Paysera</title>
<script src="https://developers-old.paysera.com/bundles/evpwallet/downloads/WebToPayWallet.min.js"></script>
<script>
WebToPayWallet.init({
'client_id': 'wkVd93h2uS',
'language': 'en'
});
</script>
<style>
#loginBtn {
color: white;
font-size: 17px;
background: #136c9c;
border-radius: 3px;
padding: 11px 24px 14px 10px;
cursor: pointer;
border: none;
}
#loginBtn img {
padding: 3px 8px 3px 0;
border-right: 1px solid #417b9a;
vertical-align: middle;
}
#loginBtn span {
padding-left: 16px;
vertical-align: middle;
}
</style>
</head>
<body>
<button id="loginBtn" onclick="loginWithPaysera()">
<img src="https://static.paysera.com/assets/image/donate-button/paysera-sign-v1.png" />
<span>Login with Paysera</span>
</button>
<script>
function loginWithPaysera() {
WebToPayWallet.openDialog('/oauth-handler.php', {
success: function() {
window.location.reload();
},
reject: function() {
alert('Login cancelled');
},
error: function() {
alert('Login failed');
}
});
}
</script>
</body>
</html>
OAuth Handler (oauth-handler.php)
<?php
session_start();
require_once 'vendor/autoload.php';
use Paysera\WalletApi\ClientFactory;
$clientId = 'wkVd93h2uS';
$secret = 'IrdTc8uQodU7PRpLzzLTW6wqZAO6tAMU';
$api = ClientFactory::create([
'auth' => ['mac' => [
'mac_id' => $clientId,
'mac_secret' => $secret,
]],
]);
$oauth = $api->oauthConsumer();
try {
$token = $oauth->getOAuthAccessToken();
if ($token) {
$_SESSION['token'] = $token;
$client = $api->walletClientWithToken($token);
$user = $client->getUser();
// Save user to database/session
$_SESSION['user_id'] = $user->getId();
$_SESSION['user_email'] = $user->getEmail();
echo '<script src="WebToPayWallet.js"></script>';
echo '<script>WebToPayWallet.sendMessageToParent("success", "/dashboard");</script>';
} else {
$scopes = [\Paysera\WalletApi\OAuth\Consumer::SCOPE_EMAIL];
$authUrl = $oauth->getAuthorizationUri($scopes);
header('Location: ' . $authUrl);
}
} catch (Exception $e) {
echo '<script src="WebToPayWallet.js"></script>';
echo '<script>WebToPayWallet.sendMessageToParent("error", "/login");</script>';
}
Flask Example
from flask import Flask, redirect, request, session
import requests
import hmac
import hashlib
import base64
import time
app = Flask(__name__)
app.secret_key = 'your-secret-key'
CLIENT_ID = 'wkVd93h2uS'
MAC_SECRET = 'IrdTc8uQodU7PRpLzzLTW6wqZAO6tAMU'
def generate_mac(method, uri, host, port, mac_key, ext=''):
timestamp = str(int(time.time()))
nonce = 'random_nonce_' + str(time.time())
normalized = '\n'.join([
timestamp, nonce, method, uri, host, str(port), ext, ''
])
mac = base64.b64encode(hmac.new(
mac_key.encode(),
normalized.encode(),
hashlib.sha256
).digest()).decode('utf-8')
return {
'id': CLIENT_ID,
'ts': timestamp,
'nonce': nonce,
'mac': mac,
'ext': ext
}
@app.route('/login')
def login():
auth_url = (
'https://www.paysera.com/frontend/oauth?'
'response_type=code&'
f'client_id={CLIENT_ID}&'
'redirect_uri=http://localhost:5000/callback&'
'scope=email+name'
)
return redirect(auth_url)
@app.route('/callback')
def callback():
code = request.args.get('code')
# Exchange code for token
mac_params = generate_mac(
'POST',
'/oauth/v1/token',
'wallet.paysera.com',
443,
MAC_SECRET
)
headers = {
'Authorization': f'MAC id="{mac_params["id"]}", '
f'ts="{mac_params["ts"]}", '
f'nonce="{mac_params["nonce"]}", '
f'mac="{mac_params["mac"]}"'
}
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': 'http://localhost:5000/callback'
}
response = requests.post(
'https://wallet.paysera.com/oauth/v1/token',
headers=headers,
data=data
)
token_data = response.json()
session['access_token'] = token_data['access_token']
session['mac_key'] = token_data['mac_key']
return redirect('/profile')
@app.route('/profile')
def profile():
if 'access_token' not in session:
return redirect('/login')
# Get user info
mac_params = generate_mac(
'GET',
'/rest/v1/user/me',
'wallet.paysera.com',
443,
session['mac_key']
)
headers = {
'Authorization': f'MAC id="{session["access_token"]}", '
f'ts="{mac_params["ts"]}", '
f'nonce="{mac_params["nonce"]}", '
f'mac="{mac_params["mac"]}"'
}
response = requests.get(
'https://wallet.paysera.com/rest/v1/user/me',
headers=headers
)
user = response.json()
return f"Welcome, {user.get('display_name')}!"
if __name__ == '__main__':
app.run(debug=True)
Advanced Topics
Available Scopes
| Scope | Description |
|---|---|
email | User's email address |
phone | User's phone number |
full_name | User's full name |
identity | Personal identity information |
address | User's address |
balance | Wallet balance (requires additional permissions) |
statements | Transaction history (requires additional permissions) |
Security Best Practices
Do:
- ✅ Validate state parameter to prevent CSRF attacks
- ✅ Store MAC secret securely (environment variables)
- ✅ Use HTTPS for all redirects
- ✅ Implement token refresh logic
- ✅ Handle errors gracefully
Don't:
- ❌ Don't expose MAC secret in client-side code
- ❌ Don't skip state parameter validation
- ❌ Don't store tokens in localStorage (use secure cookies)
- ❌ Don't ignore token expiration
Testing
Production Testing:
$api = ClientFactory::create([
'auth' => ['mac' => [
'mac_id' => 'your_client_id',
'mac_secret' => 'your_secret',
]],
'base_url' => 'https://wallet.paysera.com/rest/v1/',
]);
OAuth testing is done in production. Test thoroughly with real accounts before full deployment.
Troubleshooting
Redirect URI mismatch
- Ensure redirect_uri matches exactly in both authorization and token requests
- Check if URI is registered in Paysera system
Invalid grant
- Authorization code can only be used once
- Code expires after 10 minutes
Token expired
- Implement token refresh logic
- Request new authorization if refresh fails
Resources
- OAuth 2.0 Specification - Full OAuth docs
- User Resource - User data structure
- PHP Library - PHP SDK
- JavaScript SDK - JavaScript library
Next Steps
After implementing Login with Paysera:
- Add user profile management
- Implement session handling
- Set up user database
- Add logout functionality
Test thoroughly before full deployment to ensure OAuth flow works correctly!