Skip to main content
Mini Apps run inside the Rebell SuperApp but execute in a client-side sandbox. For security and compliance reasons, the Mini App must be treated as an untrusted client, and every call from the Mini App to the merchant backend must be authenticated and authorized. This section describes the Rebell authorization-code pattern used to establish a trusted user context on the backend. This is the foundation for all other backend operations (orders, user profile access, payments, etc.).

Trust Model Overview

Actors

User

Rebell customer using the SuperApp

Mini App

Runs in Rebell SuperApp (untrusted)

Merchant Backend

Trusted system of record

Rebell OpenAPI

Trusted authorization provider

Key Rule

  • The Mini App can request authorization and carry an authorization code, but it cannot validate it
  • The Merchant Backend must exchange the code with Rebell OpenAPI to obtain a trusted user context

Why Mini Apps Cannot Be Trusted

Mini Apps must not be trusted because:
RiskDescription
EnvironmentThey run on end-user devices (modifiable environment)
ReplayRequests can be replayed or forged
TamperingUser identity fields can be tampered with
SecretsSecrets cannot be safely stored client-side
Therefore:
  • The backend must never trust userId or similar identifiers coming from the Mini App payload
  • The backend must use server-side verification via Rebell OpenAPI

Authorization Code (authCode) Concept

An authCode is a short-lived, single-use authorization artifact issued by Rebell after user consent.

Properties

PropertyDescription
Short-livedExpires quickly (typically minutes)
Single-useCannot be reused after exchange
BoundTied to user session, Mini App, and requested scopes

What authCode Is NOT

The authCode expires quickly and cannot be stored for later use

What authCode Is Used For

To let the Merchant Backend exchange it for a trusted user context (and optionally a platform access token / user identifiers, depending on scope).

End-to-End Authorization Flow

Sequence Diagram

Flow Steps

1

Mini App Requests Authorization

Mini App calls JSAPI to request user authorization with specific scopes
my.getAuthCode({
  scopes: ['auth_user'],
  success: (res) => {
    const authCode = res.authCode;
    bootstrapSession(authCode);
  }
});
2

User Grants Consent

Platform shows consent prompt; user approves or denies
3

Mini App Receives authCode

Platform returns short-lived, single-use authCode
4

Mini App Sends to Backend

Mini App sends authCode to merchant backend bootstrap endpoint
5

Backend Exchanges authCode

Backend exchanges authCode with Rebell OpenAPI (server-to-server, signed)
6

Backend Establishes Session

Backend creates internal session and returns session identifier to Mini App

Result

The backend now has a verified user context and can securely act on behalf of that user, within granted scopes.

Backend Token Exchange & Validation

Exchange Step (Mandatory)

When the backend receives authCode, it must:
1

Validate Format

Validate basic format (non-empty, expected length)
2

Exchange with Rebell

Exchange it with Rebell OpenAPI (server-to-server, signed request)
3

Validate Response

Validate the response:
  • Mini App identifier (if provided)
  • Granted scopes match what is required
  • Token/user context is not expired
4

Create Session

Persist a backend session context

Backend Exchange Implementation

app.post('/session/bootstrap', async (req, res) => {
  const { authCode, miniAppId, deviceId } = req.body;

  // 1. Validate authCode format
  if (!authCode || authCode.length < 10) {
    return res.status(400).json({ error: 'Invalid authCode' });
  }

  try {
    // 2. Exchange authCode with Rebell OpenAPI
    const rebellResponse = await rebellClient.post('/v1/miniapp/auth/token', {
      grantType: 'authorization_code',
      code: authCode
    });

    const { userId, accessToken, scopes, expiresIn } = rebellResponse.data;

    // 3. Validate scopes
    if (!scopes.includes('auth_user')) {
      return res.status(403).json({ error: 'Required scope not granted' });
    }

    // 4. Create backend session
    const session = await createSession({
      rebellUserId: userId,
      scopesGranted: scopes,
      expiresAt: Date.now() + expiresIn * 1000,
      miniAppId,
      deviceId
    });

    // 5. Return session to Mini App
    res.cookie('sessionId', session.id, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict'
    });

    res.json({ success: true });

  } catch (error) {
    console.error('Auth exchange failed:', error);
    res.status(401).json({ error: 'Authorization failed' });
  }
});

What the Backend Should Store

Store a backend session record like:
FieldDescription
sessionIdYour internal session identifier
rebellUserIdStable user identifier from OpenAPI
scopesGrantedList of granted authorization scopes
issuedAtWhen the session was created
expiresAtWhen the session expires
miniAppId(Optional) Mini App identifier
deviceId(Optional) Device identifier

Session Establishment Patterns

Choose one approach:
Important:
  • The Mini App must not send authCode again after bootstrap
  • The backend must treat authCode as single-use

Using the Authenticated Context

Once a session is established, every request from Mini App to backend should rely on the backend session to identify the user — not on client-provided identifiers.

Authenticated Request Flow

Backend Implementation

app.get('/profile', async (req, res) => {
  // Get session from cookie or header
  const sessionId = req.cookies.sessionId ||
                    req.headers.authorization?.replace('Bearer ', '');

  if (!sessionId) {
    return res.status(401).json({ error: 'Not authenticated' });
  }

  // Resolve session to user context
  const session = await getSession(sessionId);

  if (!session || session.expiresAt < Date.now()) {
    return res.status(401).json({ error: 'Session expired' });
  }

  // Use rebellUserId from session - NEVER from request body
  const userProfile = await getUserProfile(session.rebellUserId);

  res.json(userProfile);
});
Key backend rule: Any request requiring user identity must use rebellUserId from session context, never from client-provided values.

Payments Built on Top of Backend Authorization

Payments inside Mini Apps should follow the same trust pattern:
1

Mini App Triggers

The Mini App triggers a payment action
2

Backend Creates Payment

The backend creates the payment (using session’s rebellUserId)
3

Webhook Confirms

The backend receives webhook confirmation
4

UI Updates

The Mini App UI updates based on backend-confirmed state

Payment Flow Sequence

Security Rules & Anti-Patterns

Hard Rules

Never:
  • Store secrets or private keys in Mini App code
  • Call Rebell OpenAPI directly from the Mini App
  • Trust userId or similar fields from the Mini App request body
  • Use authCode as a long-lived token
  • Mark order as paid based on client callback instead of webhook
Always:
  • Exchange authCode server-side and derive identity from OpenAPI response
  • Validate webhook signatures for payment confirmation
  • Use session context for user identity in all backend operations
  • Enforce session expiry and require re-authorization when needed

Anti-Patterns to Avoid

Anti-PatternRiskCorrect Approach
Using authCode as long-lived tokenReplay attacksExchange immediately, use session
Passing rebellUserId from clientIdentity spoofingGet from session context only
Creating payments client-sideUnauthorized paymentsCreate via backend
Trusting client payment callbackFalse successWait for webhook

Backend Endpoint Reference

Bootstrap Endpoint

POST /session/bootstrap
Request:
{
  "authCode": "string (required)",
  "miniAppId": "string (optional)",
  "deviceId": "string (optional)",
  "clientInfo": "object (optional)"
}
Responses:
StatusDescription
200 OKSession established, returns cookie/token
400 Bad RequestInvalid authCode format
401 UnauthorizedauthCode exchange failed
403 ForbiddenRequired scope not granted

Backend Must Enforce

Never accept the same authCode twice. Mark as used after successful exchange.
Don’t allow user-info access if scope not granted. Validate scopes match requirements.
If session expired, require re-authorization. Don’t extend sessions indefinitely.
Same paymentRequestId rules as Payment Integration chapter. Prevent duplicate payments.

Testing Authentication Flow

Test Checklist

  • User grants authorization
  • authCode exchanged successfully
  • Session created with correct user context
  • Subsequent requests use session correctly
  • User denies authorization
  • Invalid authCode format
  • Expired authCode
  • authCode reuse attempt
  • Session expiration
  • Client-provided userId is ignored
  • authCode cannot be replayed
  • Session is properly invalidated
  • Scopes are enforced

Next Steps

With backend authentication implemented, you can now integrate payments: