Skip to main content

Authentication

OAuth 2.0 Flows There are 4 different OAuth 2 authenticaiton mechanism available and each with specific use case:
  • Device Code Authorization
    • For dumb terminal authentication
    • Use this when your target customer’s authentication device has limited capability
    • Example includes customers with no sophisticated phones but have access to USSD or SMS
    • It allows customers to authentication and give consent over dumb channels
  • Authorization Code Flow
    • For smart terminals
    • Use this for web applications where ther eis a backend that can exchange the generated authorisation code for a token
    • Bakend can securle store your cleint id and client secret away from the web browser
  • Authorization Code Flow with PKCE (Proof Key for Code Exchange)
    • For browser/untrusted applications e.g. Single Page Application
    • Use this when you are developing a single page application (SPA) for enhanced security
  • Client Credentials
    • Use this when calling API that does not require Customer consent
    • Example includes APIs like: Open new Account, Get Biller Categoryies, Get Billers etc

API Authentication

After obtaining your acess token via the OAuth 2 flow described earlier, use the obtained acess token to access the APIs. All API calls require:
  • Authorization: Bearer <access_token> - OAuth 2.0 access token
  • signature: <signature> - Request signature for security
  • idempotency_key: <idempotency_key> - Unique identifier for request deduplication

Authorization Endpoint

Request

GET /oauth/authorize

Parameters

ParameterTypeRequiredDescription
client_idstringYesYour application’s client ID
redirect_uristringYesYour registered redirect URI during dynamic client registration
response_typestringYesMust be code
scopestringYesSpace-separated list of requested scopes
statestringNoRandom string to prevent CSRF attacks
code_challengestringYesPKCE code challenge
code_challenge_methodstringYesMust be S256

Example Request


// Authorisation via PKCE challenge
const generatePKCE = () => {
  const codeVerifier = crypto.randomUUID();
  const codeChallenge = btoa(codeVerifier);
  return { codeVerifier, codeChallenge };
};

// Step 1: Redirect user to authorization URL
const { codeVerifier, codeChallenge } = generatePKCE();
const authUrl = `${AUTH_BASE_URL}/oauth/authorize?` +
  `client_id=${credentials.client_id}&` +
  `redirect_uri=${encodeURIComponent(credentials.redirect_urls[0])}&` +
  `response_type=code&` +
  `scope=accounts payments&` +
  `code_challenge=${codeChallenge}&` +
  `code_challenge_method=S256`;

window.location.href = authUrl;

// Step 2: Exchange authorization code for access token
const exchangeCodeForToken = async (code) => {
  const response = await fetch('${AUTH_BASE_URL}/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: credentials.client_id,
      client_secret: credentials.client_secret,
      code: code,
      redirect_uri: credentials.redirect_urls[0],
      code_verifier: codeVerifier
    })
  });

  const tokenData = await response.json();
  return tokenData.access_token;
};

Token Endpoint

Request

POST /oauth/token

Parameters

ParameterTypeRequiredDescription
grant_typestringYesMust be authorization_code
client_idstringYesYour application’s client ID
client_secretstringYesYour application’s client secret
codestringYesAuthorization code from previous step
redirect_uristringYesMust match the one used in authorization
code_verifierstringYesPKCE code verifier

Example Request


// Exchange authorization code for access token
const exchangeCodeForToken = async (code) => {
  const response = await fetch('${AUTH_BASE_URL}/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: credentials.client_id,
      client_secret: credentials.client_secret,
      code: code,
      redirect_uri: credentials.redirect_urls[0],
      code_verifier: codeVerifier
    })
  });

  const tokenData = await response.json();
  return tokenData.access_token;
};

Response

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "refresh_token_here",
  "scope": "accounts payments"
}

PKCE Implementation

PKCE (Proof Key for Code Exchange) adds an extra layer of security to the OAuth flow. Here’s how to implement it:
// Generate PKCE challenge and verifier
const generatePKCE = () => {
  const codeVerifier = crypto.randomUUID();
  const codeChallenge = btoa(codeVerifier);
  return { codeVerifier, codeChallenge };
};

// Store code verifier securely (session storage, etc.)
const { codeVerifier, codeChallenge } = generatePKCE();
sessionStorage.setItem('code_verifier', codeVerifier);

// Use code challenge in authorization request
const authUrl = `https://sandbox-api.sparkle.ng/oauth/authorize?` +
  `client_id=${clientId}&` +
  `redirect_uri=${encodeURIComponent(redirectUri)}&` +
  `response_type=code&` +
  `scope=accounts payments&` +
  `code_challenge=${codeChallenge}&` +
  `code_challenge_method=S256`;

// Retrieve code verifier for token exchange
const storedCodeVerifier = sessionStorage.getItem('code_verifier');

Available Scopes

ScopeDescriptionAccess Level
accountsRead account information and balancesAccount data access
paymentsInitiate payments and transfersPayment initiation
transactionsRead transaction historyTransaction data access
standing_ordersManage standing ordersStanding order management

Using Access Tokens

Once you have an access token, include it in the Authorization header for all API requests:
curl -X GET https://sandbox-api.sparkle.ng/accounts \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Participant-ID: YOUR_PARTICIPANT_ID" \
  -H "X-Connection-ID: YOUR_CONNECTION_ID"

Token Refresh

Access tokens expire after 1 hour. Use the refresh token to get a new access token:
curl -X POST https://sandbox-api.sparkle.ng/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token&client_id=your_client_id&client_secret=your_client_secret&refresh_token=your_refresh_token"

Security Best Practices

1. Secure Storage

  • Store client secrets server-side only
  • Use environment variables for sensitive data
  • Never expose credentials in client-side code

2. Token Management

  • Store access tokens securely
  • Implement automatic token refresh
  • Clear tokens on logout

3. PKCE Implementation

  • Always use PKCE for web applications
  • Generate cryptographically secure random values
  • Store code verifier securely during the flow

4. Redirect URI Validation

  • Use exact redirect URI matching
  • Avoid wildcard redirect URIs
  • Validate redirect URIs server-side

5. State Parameter

  • Always include a random state parameter
  • Validate state parameter on callback
  • Use cryptographically secure random values

Error Handling

Common OAuth errors and how to handle them:
ErrorDescriptionSolution
invalid_clientInvalid client credentialsCheck your client_id and client_secret
invalid_grantInvalid authorization codeEnsure code is used only once and not expired
invalid_redirect_uriRedirect URI mismatchVerify redirect URI matches registration
invalid_scopeInvalid scope requestedCheck scope format and permissions
access_deniedUser denied consentHandle gracefully and retry
Always implement proper error handling and provide clear feedback to users when authentication fails.

Testing Authentication

Use our sandbox environment to test your authentication implementation:
  1. Register your application in sandbox
  2. Test the complete OAuth flow
  3. Verify token exchange and API calls
  4. Test error scenarios and edge cases