npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dineengine/spendgo-oauth

v1.0.0

Published

Performs OAuth for the Spendgo OAuth APIs

Downloads

34

Readme

@dineengine/spendgo-oauth

Performs OAuth for the Spendgo OAuth APIs

Install

npm install @dineengine/spendgo-oauth
npx cap sync

Usage Example

import { DineEngineSpendgoOAuth } from '@dineengine/spendgo-oauth';

// Configure the OAuth client
await DineEngineSpendgoOAuth.configure({
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret', // See security section below
  redirectUri: 'com.yourapp.scheme://oauth',
  sandbox: true, // true for sandbox (skuped.com), false for production (spendgo.com)
  scopes: ['read', 'write'] // optional, defaults to ['read']
});

// Start OAuth flow
try {
  const result = await DineEngineSpendgoOAuth.authorize();
  
  if (result.success) {
    console.log('Access Token:', result.tokens.access_token);
    console.log('Refresh Token:', result.tokens.refresh_token);
    console.log('Expires at:', new Date(result.tokens.access_token_expires_on));
  } else {
    console.error('OAuth failed:', result.error);
  }
} catch (error) {
  console.error('OAuth error:', error);
}

// Check token status
const status = await DineEngineSpendgoOAuth.getTokenStatus();
console.log('Token is valid:', status.isValid);

// Refresh token when needed
if (!status.isValid) {
  const refreshResult = await DineEngineSpendgoOAuth.refreshToken();
  if (refreshResult.success) {
    console.log('Token refreshed successfully');
  }
}

// Get current access token
const { token } = await DineEngineSpendgoOAuth.getAccessToken();
console.log('Current access token:', token);

// Logout and clear tokens
await DineEngineSpendgoOAuth.logout();

Security: Client Secret Storage

⚠️ IMPORTANT: Never hardcode client secrets in your application code. Client secrets must be stored securely and injected at build time.

Recommended Approach: Environment Variables

iOS Setup (Info.plist)

  1. Add your client secret to your iOS Info.plist:
<key>SpendgoClientSecret</key>
<string>$(SPENDGO_CLIENT_SECRET)</string>
  1. Set the environment variable in your Xcode build settings or CI/CD:
export SPENDGO_CLIENT_SECRET="your-actual-client-secret"
  1. Read the value in your app:
import { NativeSettings } from '@capacitor/core';

const clientSecret = await NativeSettings.get({ key: 'SpendgoClientSecret' });
// Or use Capacitor's Preferences plugin

Android Setup (BuildConfig)

  1. Add to your android/app/build.gradle:
android {
    defaultConfig {
        buildConfigField "String", "SPENDGO_CLIENT_SECRET", "\"${System.getenv('SPENDGO_CLIENT_SECRET') ?: 'default-dev-secret'}\""
    }
}
  1. Access in your app via a native method or create a helper:
public class ConfigHelper {
    public static String getClientSecret() {
        return BuildConfig.SPENDGO_CLIENT_SECRET;
    }
}

Alternative: Secure Storage Plugin

For runtime configuration, use a secure storage plugin:

npm install @capacitor-community/secure-storage
import { SecureStoragePlugin } from '@capacitor-community/secure-storage';

// Store securely (one-time setup)
await SecureStoragePlugin.set({
  key: 'spendgo_client_secret',
  value: 'your-client-secret'
});

// Retrieve for OAuth configuration
const { value: clientSecret } = await SecureStoragePlugin.get({
  key: 'spendgo_client_secret'
});

What NOT to do:

Never do this:

// DON'T hardcode secrets in source code
const clientSecret = 'sk_live_1234567890abcdef'; // This will be visible in your app bundle

Never store in:

  • Plain text files
  • JavaScript constants
  • Git repositories
  • Client-side configuration files

Configuration

iOS Setup

Add the following to your Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>OAuth</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>com.yourapp.scheme</string>
    </array>
  </dict>
</array>

Android Setup

  1. Add OAuth redirect scheme to your AndroidManifest.xml:

Add an intent filter to your main activity to handle OAuth redirects:

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleTask">
    
    <!-- Your existing intent filters -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    
    <!-- OAuth redirect handler -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="com.yourapp.scheme" />
    </intent-filter>
</activity>
  1. Configure manifest placeholders in android/app/build.gradle:
android {
    defaultConfig {
        applicationId "com.yourapp.package"
        // ... other config
        
        // OAuth redirect scheme configuration
        manifestPlaceholders = [
            appAuthRedirectScheme: 'com.yourapp.scheme'
        ]
    }
}

Note: Replace com.yourapp.scheme with your actual app's package name or a custom scheme (e.g., com.mycompany.myapp).

MainActivity Setup (Required for Android)

For OAuth redirects to work properly on Android, you need to modify your MainActivity.java to handle OAuth redirect intents. This is required because the OAuth flow returns to your app via a deep link, and the MainActivity needs to pass this intent to the OAuth plugin.

Update your MainActivity.java:

package com.yourapp.package; // Replace with your actual package name

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.PluginHandle;
import com.dineengine.plugins.spendgooauth.DineEngineSpendgoOAuthPlugin;

public class MainActivity extends BridgeActivity {
    
    private static final String TAG = "MainActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Log.d(TAG, "MainActivity onCreate called");
        
        // Handle OAuth redirect if the app was launched with an intent
        handleOAuthRedirect(getIntent());
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        
        Log.d(TAG, "MainActivity onNewIntent called");
        
        // Handle OAuth redirect when the app is already running
        handleOAuthRedirect(intent);
    }
    
    private void handleOAuthRedirect(Intent intent) {
        if (intent == null) {
            Log.d(TAG, "Intent is null, skipping OAuth redirect handling");
            return;
        }
        
        Uri data = intent.getData();
        Log.d(TAG, "Intent data: " + (data != null ? data.toString() : "null"));
        
        if (data != null && "com.yourapp.scheme".equals(data.getScheme())) {
            Log.d(TAG, "OAuth redirect detected, passing to plugin");
            
            // This is an OAuth redirect, pass it to the OAuth plugin
            PluginHandle pluginHandle = getBridge().getPlugin("DineEngineSpendgoOAuth");
            if (pluginHandle != null && pluginHandle.getInstance() instanceof DineEngineSpendgoOAuthPlugin) {
                DineEngineSpendgoOAuthPlugin oauthPlugin = (DineEngineSpendgoOAuthPlugin) pluginHandle.getInstance();
                oauthPlugin.handleOAuthRedirect(intent);
                Log.d(TAG, "OAuth redirect passed to plugin successfully");
            } else {
                Log.e(TAG, "OAuth plugin not found or wrong type");
            }
        } else {
            Log.d(TAG, "Not an OAuth redirect, ignoring");
        }
    }
}

Important Notes:

  1. Replace com.yourapp.package with your actual package name (should match your applicationId in build.gradle)
  2. Replace com.yourapp.scheme with the same scheme you used in your AndroidManifest.xml and redirectUri configuration
  3. Ensure your AndroidManifest.xml has android:launchMode="singleTask" for the MainActivity (this is usually set by default in Capacitor apps)

Why This is Required:

The OAuth flow works as follows:

  1. Your app opens the OAuth provider in a Custom Tab
  2. User completes authentication
  3. OAuth provider redirects to your app using the configured scheme (e.g., com.yourapp.scheme://oauth)
  4. Android opens your app with this deep link intent
  5. Your MainActivity receives the intent and must pass it to the OAuth plugin
  6. The plugin processes the authorization code and exchanges it for tokens

Without this MainActivity setup, the OAuth redirect will return to your app but the plugin won't receive the authorization response, causing the OAuth flow to hang.

Environment Configuration

Sandbox vs Production

The plugin supports two environments:

  • Sandbox (sandbox: true): Uses skuped.com for testing
  • Production (sandbox: false): Uses spendgo.com for live transactions

Configure based on your build environment:

const isProduction = process.env.NODE_ENV === 'production';

await DineEngineSpendgoOAuth.configure({
  clientId: 'your-client-id',
  clientSecret: getClientSecret(), // Use secure method above
  redirectUri: 'com.yourapp.scheme://oauth',
  sandbox: !isProduction, // true for development, false for production
  scopes: ['read', 'write']
});

SpendGo API Integration

This plugin provides OAuth authentication for the SpendGo API. Once authenticated, you can use the access token to make API calls to SpendGo's services:

  • Member Profile: GET /member/profile
  • Member Balance: GET /member/balance
  • Member Rewards: GET /member/rewards
  • And more...

Example API Call

const { token } = await DineEngineSpendgoOAuth.getAccessToken();

const response = await fetch('https://identity.spendgo.com/v3/member/profile', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

const memberData = await response.json();

See the SpendGo API Documentation for complete API reference.

API

configure(...)

configure(config: SpendgoOAuthConfig) => Promise<void>

Configure the OAuth client with SpendGo credentials

| Param | Type | | ------------ | ----------------------------------------------------------------- | | config | SpendgoOAuthConfig |


authorize()

authorize() => Promise<SpendgoAuthResult>

Start the OAuth authorization flow

Returns: Promise<SpendgoAuthResult>


refreshToken()

refreshToken() => Promise<SpendgoRefreshResult>

Refresh the access token using the refresh token

Returns: Promise<SpendgoRefreshResult>


getTokenStatus()

getTokenStatus() => Promise<SpendgoTokenStatus>

Get the current token status

Returns: Promise<SpendgoTokenStatus>


logout()

logout() => Promise<SpendgoLogoutResult>

Logout and clear stored tokens

Returns: Promise<SpendgoLogoutResult>


getAccessToken()

getAccessToken() => Promise<{ token?: string; }>

Get the stored access token

Returns: Promise<{ token?: string; }>


clearTokens()

clearTokens() => Promise<void>

Clear all stored tokens and configuration


Interfaces

SpendgoOAuthConfig

| Prop | Type | | ------------------ | --------------------- | | clientId | string | | clientSecret | string | | redirectUri | string | | sandbox | boolean | | scopes | string[] |

SpendgoAuthResult

| Prop | Type | | ------------- | --------------------------------------------------------------------- | | success | boolean | | tokens | SpendgoTokenResponse | | error | string |

SpendgoTokenResponse

| Prop | Type | | ----------------------------------- | ------------------- | | token_type | string | | scope | string | | access_token | string | | access_token_expires_in_secs | number | | access_token_expires_on | number | | refresh_token | string | | refresh_token_expires_in_secs | number | | refresh_token_expires_on | number |

SpendgoRefreshResult

| Prop | Type | | ------------- | --------------------------------------------------------------------- | | success | boolean | | tokens | SpendgoTokenResponse | | error | string |

SpendgoTokenStatus

| Prop | Type | | ---------------------- | -------------------- | | isValid | boolean | | accessToken | string | | refreshToken | string | | expiresAt | number | | refreshExpiresAt | number |

SpendgoLogoutResult

| Prop | Type | | ------------- | -------------------- | | success | boolean | | error | string |