Skip to main content
Social auth is a two-step process: you redirect the user to the provider login page, then exchange a short-lived code for a refresh token once they return.

Setup (one-time, in the dashboard)

Before using these endpoints you need to configure the OAuth provider in your project:
  1. Go to Project Settings and add your frontend URL as the Site URL (e.g., https://myapp.com).
  2. Go to Auth → Social Auth and select GitHub or Google.
  3. Copy the read-only Callback URL shown by urBackend (e.g., https://api.ub.bitbros.in/api/userAuth/social/github/callback).
  4. Register that callback URL in the provider’s OAuth app settings (GitHub: Developer Settings → OAuth Apps; Google: Cloud Console → Credentials).
  5. Paste the provider’s Client ID and Client Secret into urBackend and enable the provider.

Step 1 — Start the OAuth Flow

GET /api/userAuth/social/:provider/start

Redirects the user’s browser to the provider login page. Because this is a browser redirect (not a fetch call), pass your API key as a query parameter.
provider
string
required
OAuth provider name. Accepted values: github, google.
x-api-key
string
required
Your pk_live_… key. Can also be sent as a header if you are making a non-redirect request.
Response: HTTP redirect to the provider login page. The browser handles this automatically.
// Redirect the user to start the OAuth flow
window.location.href =
  'https://api.ub.bitbros.in/api/userAuth/social/github/start?x-api-key=pk_live_YOUR_KEY';

// Or for Google:
window.location.href =
  'https://api.ub.bitbros.in/api/userAuth/social/google/start?x-api-key=pk_live_YOUR_KEY';
After the user authenticates with the provider, urBackend redirects them to:
https://your-site.com/auth/callback?rtCode=abc&provider=github&userId=u1&isNewUser=false&linkedByEmail=false#token=eyJ...
ParamLocationDescription
tokenURL fragment (#)Access token (JWT) — use for API calls
rtCodeQuery stringOne-time code to exchange for a refresh token
providerQuery stringgithub or google
userIdQuery stringThe user’s ID in your database
isNewUserQuery stringtrue if the account was just created
linkedByEmailQuery stringtrue if an existing account was linked by email
errorQuery stringError message — only present on failure
The access token is placed in the URL fragment (#...) intentionally. Fragments are never sent to servers in HTTP requests, which prevents token leakage through referrer headers or server logs.

Step 2 — Exchange rtCode for a Refresh Token

POST /api/userAuth/social/exchange

Your /auth/callback page must call this endpoint to convert the one-time rtCode into a long-lived refresh token.
rtCode is one-time use and expires in 60 seconds. Exchange it immediately when your callback page loads.

Required Headers

HeaderValue
x-api-keyYour pk_live_… key
Content-Typeapplication/json

Request Body

token
string
required
The access token extracted from the URL fragment (#token=…).
rtCode
string
required
The one-time exchange code from the query string (?rtCode=…).

Response Fields

success
boolean
true when the exchange succeeded.
data
object
message
string
Human-readable status message.

Full Callback Page Example

// pages/AuthCallback.jsx (React)
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

function AuthCallback() {
  const navigate = useNavigate();

  useEffect(() => {
    async function handleCallback() {
      const queryParams = new URLSearchParams(window.location.search);
      const error = queryParams.get('error');

      if (error) {
        console.error('OAuth error:', error);
        navigate('/login');
        return;
      }

      // Extract token from fragment, rtCode from query string
      const hashParams = new URLSearchParams(window.location.hash.slice(1));
      const accessToken = hashParams.get('token');
      const rtCode = queryParams.get('rtCode');

      if (!accessToken || !rtCode) {
        navigate('/login');
        return;
      }

      // Exchange rtCode for refresh token
      const res = await fetch('https://api.ub.bitbros.in/api/userAuth/social/exchange', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': 'pk_live_YOUR_KEY'
        },
        body: JSON.stringify({ token: accessToken, rtCode })
      });

      const { success, data } = await res.json();

      if (!success) {
        navigate('/login');
        return;
      }

      // Store tokens and proceed
      localStorage.setItem('accessToken', accessToken);
      localStorage.setItem('refreshToken', data.refreshToken);
      navigate('/dashboard');
    }

    handleCallback();
  }, [navigate]);

  return <div>Completing login…</div>;
}

export default AuthCallback;

Success Response

{
  "success": true,
  "data": {
    "refreshToken": "REFRESH_TOKEN_VALUE"
  },
  "message": "Refresh token exchanged successfully"
}

Error Responses

{ "success": false, "data": {}, "message": "rtCode and token are required" }
{ "success": false, "data": {}, "message": "Invalid or expired refresh token exchange code" }