diff --git a/messages/auth.json b/messages/auth.json
index 4fe5ed4da8..c316ab70a0 100644
--- a/messages/auth.json
+++ b/messages/auth.json
@@ -9,5 +9,6 @@
"PortInUseAction": "Kill the process running on port %s or use a custom connected app and update OauthLocalPort in the sfdx-project.json file.",
"invalidRequestMethod": "Invalid request method: %s",
"invalidRequestUri": "Invalid request uri: %s",
- "pollingTimeout": "The device authorization request timed out. After executing force:auth:device:login, you must approve access to the device within 10 minutes. This can happen if the URL wasn’t copied into the browser, login was not attempted, or the 2FA process was not completed within 10 minutes. Request authorization again."
+ "pollingTimeout": "The device authorization request timed out. After executing force:auth:device:login, you must approve access to the device within 10 minutes. This can happen if the URL wasn’t copied into the browser, login was not attempted, or the 2FA process was not completed within 10 minutes. Request authorization again.",
+ "ServerErrorHTMLResponse": "
%s
This is most likely not an error with the Salesforce CLI. Please ensure all information is accurate and try again."
}
diff --git a/src/webOAuthServer.ts b/src/webOAuthServer.ts
index cd3f19c44c..fe9afd9960 100644
--- a/src/webOAuthServer.ts
+++ b/src/webOAuthServer.ts
@@ -96,6 +96,7 @@ export class WebOAuthServer extends AsyncCreatable {
response.end();
resolve(authInfo);
} catch (err) {
+ this.webServer.reportError(err, response);
reject(err);
}
})
@@ -316,6 +317,19 @@ export class WebServer extends AsyncCreatable {
response.end(body);
}
+ /**
+ * sends a response to the browser reporting an error.
+ *
+ * @param error the error
+ * @param response the response to write the redirect to.
+ */
+ public reportError(error: Error, response: http.ServerResponse): void {
+ response.setHeader('Content-Type', 'text/html');
+ const body = messages.getMessage('ServerErrorHTMLResponse', [error.message]);
+ response.setHeader('Content-Length', Buffer.byteLength(body));
+ response.end(body);
+ }
+
protected async init(): Promise {
this.logger = await Logger.child(this.constructor.name);
}
diff --git a/test/unit/webOauthServerTest.ts b/test/unit/webOauthServerTest.ts
index 4e900dc071..259336ca72 100644
--- a/test/unit/webOauthServerTest.ts
+++ b/test/unit/webOauthServerTest.ts
@@ -8,6 +8,7 @@
import * as http from 'http';
import { expect } from 'chai';
+import { assert } from '@salesforce/ts-types';
import { StubbedType, stubInterface, stubMethod } from '@salesforce/ts-sinon';
import { Env } from '@salesforce/kit';
import { testSetup, MockTestOrgData } from '../../src/testSetup';
@@ -47,6 +48,7 @@ describe('WebOauthServer', () => {
let authInfoStub: StubbedType;
let serverResponseStub: StubbedType;
let redirectStub: sinon.SinonStub;
+ let authStub: sinon.SinonStub;
beforeEach(async () => {
authFields = await testData.getConfig();
@@ -57,7 +59,7 @@ describe('WebOauthServer', () => {
serverResponseStub = stubInterface($$.SANDBOX, {});
stubMethod($$.SANDBOX, WebOAuthServer.prototype, 'executeOauthRequest').callsFake(async () => serverResponseStub);
- stubMethod($$.SANDBOX, AuthInfo, 'create').callsFake(async () => authInfoStub);
+ authStub = stubMethod($$.SANDBOX, AuthInfo, 'create').callsFake(async () => authInfoStub);
redirectStub = stubMethod($$.SANDBOX, WebServer.prototype, 'doRedirect').callsFake(async () => {});
});
@@ -76,6 +78,21 @@ describe('WebOauthServer', () => {
expect(redirectStub.callCount).to.equal(1);
expect(redirectStub.args).to.deep.equal([[303, frontDoorUrl, serverResponseStub]]);
});
+
+ it('should report error', async () => {
+ const reportErrorStub = stubMethod($$.SANDBOX, WebServer.prototype, 'reportError').callsFake(async () => {});
+ authStub.rejects(new Error('BAD ERROR'));
+ const oauthServer = await WebOAuthServer.create({ oauthConfig: {} });
+ await oauthServer.start();
+ try {
+ await oauthServer.authorizeAndSave();
+ assert(false, 'authorizeAndSave should fail');
+ } catch (e) {
+ expect(e.message, 'BAD ERROR');
+ }
+ expect(authStub.callCount).to.equal(1);
+ expect(reportErrorStub.args[0][0].message).to.equal('BAD ERROR');
+ });
});
describe('parseAuthCodeFromRequest', () => {