Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6c2c335
Adding new controls
acrosman Jul 3, 2021
87f6e0d
Pass auth mode to main.
acrosman Jul 3, 2021
ce64da5
Refactor of login calls.
acrosman Jul 3, 2021
47f80cd
Initial draft of oauth interface (non-functional)
acrosman Jul 3, 2021
09337b4
Removed unused elements
acrosman Jul 3, 2021
8ecc59b
Fixed Login failure message
acrosman Jul 3, 2021
c90fb54
correction to partition setup
acrosman Jul 3, 2021
fa80e68
Further session correction
acrosman Jul 3, 2021
46b44e4
Revert "Further session correction"
acrosman Jul 3, 2021
25c34bf
partion name change
acrosman Jul 3, 2021
57bc59b
Merge branch 'main' into feature/add-oauth
acrosman Jan 16, 2022
ad80c65
Merge branch 'issue-54' into feature/add-oauth
acrosman Jan 16, 2022
95a2e32
minor tweaks
acrosman Mar 12, 2022
d434f52
Merge branch 'main' into feature/add-oauth
acrosman May 26, 2025
b1fc891
Finish Main back merge
acrosman May 26, 2025
a4f9304
Refactor password login into own function
acrosman May 26, 2025
4bcd394
Ensure passwords do not contain whitespace.
acrosman May 26, 2025
264060f
Switch to browser instead of local window
acrosman May 27, 2025
e12abee
Updates to use browser auth not local.
acrosman May 27, 2025
69d340d
And URL pattern filtering on open requests for better security.
acrosman May 27, 2025
28bb033
Remove extra Electron elements
acrosman May 27, 2025
ce3262e
Add schema check Login URL checker
acrosman May 27, 2025
853153a
Adding oauth test stub.
acrosman Oct 12, 2025
f4af7a9
Fix linting error
acrosman Oct 12, 2025
87792ed
Merge branch 'main' into feature/add-oauth
acrosman Apr 19, 2026
2f1922d
Merge branch 'main' into feature/add-oauth
acrosman Apr 19, 2026
f573c98
Remove unneeded tests
acrosman Apr 19, 2026
4df801b
Merge branch 'feature/add-oauth' of github.com:acrosman/Salesforce2Sq…
acrosman Apr 19, 2026
fa4cd9e
Adding oauth preferences and removing multiple connections
acrosman Apr 19, 2026
8d35f15
Update readme with OAuth instructions
acrosman Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SALESFORCE_CLIENT_ID=your_client_id_here
SALESFORCE_CLIENT_SECRET=your_client_secret_here
9 changes: 9 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ jobs:
- name: install dependencies
run: npm install
- name: build
env:
SALESFORCE_CLIENT_ID: ${{ secrets.SALESFORCE_CLIENT_ID }}
SALESFORCE_CLIENT_SECRET: ${{ secrets.SALESFORCE_CLIENT_SECRET }}
run: npm run make

build_on_mac:
Expand All @@ -27,6 +30,9 @@ jobs:
- name: install dependencies
run: npm install
- name: build
env:
SALESFORCE_CLIENT_ID: ${{ secrets.SALESFORCE_CLIENT_ID }}
SALESFORCE_CLIENT_SECRET: ${{ secrets.SALESFORCE_CLIENT_SECRET }}
run: npm run make

build_on_win:
Expand All @@ -39,4 +45,7 @@ jobs:
- name: install dependencies
run: npm install
- name: build
env:
SALESFORCE_CLIENT_ID: ${{ secrets.SALESFORCE_CLIENT_ID }}
SALESFORCE_CLIENT_SECRET: ${{ secrets.SALESFORCE_CLIENT_SECRET }}
run: npm run make
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ typings/

# dotenv environment variables file
.env
.env.local
.env.*.local

# parcel-bundler cache (https://parceljs.org/)
.cache
Expand Down
61 changes: 61 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,64 @@ This project has no direct association with Salesforce except the use of the API
## Getting Involved

If you would like to contribute to this project please feel invited to do so. Feel free to review open [issues](issues) and read the [contributing guide](contributing.md).

## OAuth Setup

Salesforce2Sql supports OAuth2 for connecting to Salesforce. To use it you will need to configure a Salesforce Connected App and then enter the client credentials into Salesforce2Sql.

### Set Up OAuth in Salesforce2Sql

1. Launch Salesforce2Sql.
2. Open the Preferences window.
3. Scroll to **Salesforce OAuth Settings**.
4. Paste in your **OAuth Client ID** and **OAuth Client Secret**.
5. Save your changes.

The client secret is stored using Electron safeStorage so it stays encrypted on your local machine.

After saving your credentials:

1. Return to the main screen.
2. Click **Create New Connection**.
3. Leave **OAuth2** selected.
4. Confirm the login URL:
- Production orgs usually use `https://login.salesforce.com`
- Sandboxes usually use `https://test.salesforce.com`
5. Click **Connect**.
6. Sign in to Salesforce in the browser and approve access when prompted.

### Set Up the Connected App in Salesforce

If you do not already have a Connected App for this tool:

1. In Salesforce, go to **Setup**.
2. Open **App Manager**.
3. Click **New Connected App**.
4. Enter the basic app details.
5. Enable **OAuth Settings**.
6. Set the callback URL to `http://localhost/completesetup`.
7. Add the OAuth scopes needed by Salesforce2Sql:
- **Access and manage your data (api)**
- **Access your basic information (id, profile, email, address, phone)**
- **Perform requests on your behalf at any time (refresh_token, offline_access)**
- **Provide access to your data via the Web (web)**
8. Save the Connected App.
9. After Salesforce finishes provisioning it, copy the **Consumer Key** and **Consumer Secret**.
10. Paste those values into the Salesforce2Sql Preferences window.

### Development and CI Option

For local development or CI, you can also provide the OAuth credentials through environment variables:

```env
SALESFORCE_CLIENT_ID=your_client_id_here
SALESFORCE_CLIENT_SECRET=your_client_secret_here
```

If both stored preferences and environment variables are present, the environment variables are used.

### Security Notes

- Do not commit real OAuth secrets to the repository.
- Do not share production Connected App secrets in screenshots or issue comments.
- Use a sandbox Connected App for development whenever possible.
83 changes: 52 additions & 31 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="consoleModalLabel">Message Console</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<button type="button" class="btn-close ms-auto" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="container-fluid">
Expand Down Expand Up @@ -58,8 +56,7 @@ <h1 class="header">
data-bs-target="#loginModal">Create New Connection</button>
</div>
<div class="card-footer" id="org-status">
<label for="active-org">Active Org for next action.</label>
<select id="active-org" class="custom-select"></select>
<p class="mb-1">Connected User: <span id="active-org-user"></span></p>
<p>Message: <span id="login-response-message"></span><br>
Org Id: <span id="active-org-id"></span></p>
<button type="button" id="logout-trigger" class="btn btn-warning" value="Logout">Logout</button>
Expand All @@ -70,44 +67,69 @@ <h1 class="header">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="loginModalLabel">Enter Salesforce Login</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<button type="button" class="btn-close ms-auto" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="login-username">User Name</label>
<input type="text" id="login-username" class="form-control"
aria-describedby="usernameHelp" placeholder="Enter Salesforce Username">
<small id="usernameHelp" class="form-text">Your Salesforce username must be
in the form of an email address.</small>
</div>
<div class="form-group">
<label for="login-password">Password</label>
<input type="password" id="login-password" class="form-control">
</div>
<div class="form-group">
<label for="login-token">Security Token</label>
<input type="password" class="form-control" aria-describedby="tokenHelp"
id="login-token">
<small id="tokenHelp" class="form-text">Likely you will need your Salesforce
Security token. If you do not have it follow <a
href='https://help.salesforce.com/articleView?id=user_security_token.htm&type=5'>these
reset instructions.</a></small>
<label for="sfconnect-radio-selectors">Select Connection Type</label>
<div class="form-check">
<input class="form-check-input" type="radio"
name="sfconnect-radio-selectors" id="sfconnect-oauth" value="oauth"
checked>
<label class="form-check-label" for="sfconnect-oauth">OAuth2</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio"
name="sfconnect-radio-selectors" id="sfconnect-password"
value="password">
<label class="form-check-label"
for="sfconnect-password">Username/Password</label>
</div>
</div>
<div class="form-group">
<label for="login-url">Login URL</label>
<input type="url" id="login-url" class="form-control"
value="https://login.salesforce.com">
</div>
<div class="alert alert-info mt-3 mb-3" id="login-oauth-wrapper">
OAuth uses the Connected App values saved in Preferences.
<div id="oauth-config-status" class="small mt-2">Set the OAuth client ID and
secret in Preferences before connecting.</div>
</div>
<div class="alert alert-warning d-none" id="login-modal-message"></div>
<div id="login-password-wrapper">
<div class="form-group">
<label for="login-username">User Name</label>
<input type="text" id="login-username" class="form-control"
aria-describedby="usernameHelp"
placeholder="Enter Salesforce Username">
<small id="usernameHelp" class="form-text">Your Salesforce username must
be
in the form of an email address.</small>
</div>
<div class="form-group">
<label for="login-password">Password</label>
<input type="password" id="login-password" class="form-control">
</div>
<div class="form-group">
<label for="login-token">Security Token</label>
<input type="password" class="form-control" aria-describedby="tokenHelp"
id="login-token">
<small id="tokenHelp" class="form-text">Likely you will need your
Saleforce
Security token. If you do not have it follow <a
href='https://help.salesforce.com/articleView?id=user_security_token.htm&type=5'>these
reset instructions.</a></small>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary"
data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="login-trigger"
data-bs-dismiss="modal">Connect</button>
<button type="button" class="btn btn-primary" id="login-trigger">Connect</button>
</div>
</div>
</div>
Expand All @@ -118,9 +140,8 @@ <h5 class="modal-title" id="loginModalLabel">Enter Salesforce Login</h5>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="dbModalLabel">Enter Database Information</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<button type="button" class="btn-close ms-auto" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
Expand Down
18 changes: 16 additions & 2 deletions app/preferences-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ document.addEventListener('DOMContentLoaded', () => {
window.api.send('preferences_load');

// Add save listener for preference window.
document.getElementById('btn-preferences-save').addEventListener('click', () => {
document.getElementById('btn-preferences-save').addEventListener('click', (event) => {
event.preventDefault();
window.api.send('preferences_save', {
theme: document.getElementById('setting-theme-select').value,
indexes: {
Expand All @@ -26,12 +27,17 @@ document.addEventListener('DOMContentLoaded', () => {
suppressReadOnly: document.getElementById('hide-readonly-fields').checked,
suppressAudit: document.getElementById('hide-audit-fields').checked,
},
oauth: {
clientId: document.getElementById('oauth-client-id').value,
clientSecret: document.getElementById('oauth-client-secret').value,
},
});
window.api.send('preferences_close');
});

// Add click to close listener for preference window.
document.getElementById('btn-preferences-close').addEventListener('click', () => {
document.getElementById('btn-preferences-close').addEventListener('click', (event) => {
event.preventDefault();
window.api.send('preferences_close');
});

Expand Down Expand Up @@ -67,4 +73,12 @@ window.api.receive('preferences_data', (data) => {
document.getElementById('default-checkbox').checked = data.defaults.checkboxDefaultFalse;
document.getElementById('hide-readonly-fields').checked = data.defaults.suppressReadOnly;
document.getElementById('hide-audit-fields').checked = data.defaults.suppressAudit;
document.getElementById('oauth-client-id').value = data.oauth?.clientId || '';
document.getElementById('oauth-client-secret').value = '';
document.getElementById('oauth-client-secret').placeholder = data.oauth?.hasClientSecret
? 'Stored securely. Leave blank to keep the current secret.'
: 'Enter Salesforce OAuth client secret';
document.getElementById('oauth-credential-status').innerText = data.oauth?.hasClientSecret
? 'OAuth client secret is stored securely.'
: 'No OAuth client secret stored yet.';
});
23 changes: 23 additions & 0 deletions app/preferences.html
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,29 @@ <h2 class="card-title h5">Index Settings</h2>
</div>
</div>
</div>
<div class="row pb-2">
<div class="col-12">
<div class="card">
<div class="card-body">
<h2 class="card-title h5">Salesforce OAuth Settings</h2>
<p class="card-text">These Connected App credentials are stored using Electron safeStorage so the secret
stays encrypted on your device.</p>
<div class="form-group pb-2">
<label for="oauth-client-id">OAuth Client ID</label>
<input type="text" class="form-control" id="oauth-client-id"
placeholder="Enter Salesforce Connected App client ID">
</div>
<div class="form-group pb-2">
<label for="oauth-client-secret">OAuth Client Secret</label>
<input type="password" class="form-control" id="oauth-client-secret"
placeholder="Enter Salesforce OAuth client secret">
<small id="oauth-credential-status" class="form-text text-muted">No OAuth client secret stored
yet.</small>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
Expand Down
Loading
Loading