Custom auth provider exception


#1

Dear all,
I get the following error while im implementing a custom auth provider, please take a look:

(node:19562) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot read property ‘warn’ of undefined

My code:

  verifyIdentifier(req) {
      const jsonData = req.body.data;
      var sfData = JSON.parse(jsonData);
  
      const httpOptions = {
         uri: sfData.id_url,
         method: this.httpMethod,
         json: true,
         headers: {
          'Authorization': 'Bearer ' + sfData.access_token
        }
       }

      return this.request(httpOptions).catch((err) => {
          throw new deps.problem.HttpProblem.Unauthorized({
            detail: `${err.toString()}`
          })
      }).then((result) => {
         return result.user_id
      })
   }

I try to replace the return block with the below one but still get the same error:

   return new Promise((resolve, reject) => {
    reject(new Error('Not implemented!'));
  });

Versions:
_Realm Object Server: 1.8.2
_Node: 6.10.3/7.10.0

Thank you so much for your time.

Best regards.


#2

Hi @komodo - for these types of issues it is probably best to open a GitHub issue on the realm mobile platform repo here: https://github.com/realm/realm-mobile-platform

If I had to guess I think you need to be parsing user_info instead of data

What does a print out of the packet look like? Can you share the JSON?


#3

Dear ian.
Here are return messages:

In case error, the err value is:

{ StatusCodeError: 403 - “Bad_OAuth_Token”
at new StatusCodeError (/xxx/realm-mobile-platform/realm-object-server/node_modules/request-promise-core/lib/errors.js:32:15)
at Request.plumbing.callback (/xxx/realm-mobile-platform/realm-object-server/node_modules/request-promise-core/lib/plumbing.js:104:33)
at Request.RP$callback [as _callback] (/xxx/realm-mobile-platform/realm-object-server/node_modules/request-promise-core/lib/plumbing.js:46:31)
at Request.self.callback (/xxx/realm-mobile-platform/realm-object-server/node_modules/request/request.js:188:22)
at emitTwo (events.js:106:13)
at Request.emit (events.js:191:7)
at Request. (/xxx/realm-mobile-platform/realm-object-server/node_modules/request/request.js:1171:10)
at emitOne (events.js:96:13)
at Request.emit (events.js:188:7)
at IncomingMessage. (/xxx/realm-mobile-platform/realm-object-server/node_modules/request/request.js:1091:12)
name: ‘StatusCodeError’,
statusCode: 403,
message: ‘403 - “Bad_OAuth_Token”’,
error: ‘Bad_OAuth_Token’,
options:
{ uri: ‘https://test.salesforce.com/services/oauth2/userinfo’,
method: ‘GET’,
json: true,
headers: { Authorization: ‘Bearer 00D63000000CpEM!xxxxxxxxxxxxxxxxxxxxxx’ },
timeout: 30000,
callback: [Function: RP$callback],
transform: undefined,
simple: true,
resolveWithFullResponse: false,
transform2xxOnly: false },
response:
IncomingMessage {
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: [Object],
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: true,
endEmitted: true,
reading: false,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
defaultEncoding: ‘utf8’,
ranOut: false,
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null },
readable: false,
domain: null,
_events:
{ end: [Object],
close: [Object],
data: [Function],
error: [Function] },
_eventsCount: 4,
_maxListeners: undefined,
socket:
TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: null,
npnProtocol: undefined,
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object],
_eventsCount: 10,
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: ‘test.salesforce.com’,
_readableState: [Object],
readable: false,
domain: null,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
destroyed: true,
_bytesDispatched: 250,
_sockname: null,
_pendingData: null,
_pendingEncoding: ‘’,
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
parser: null,
_httpMessage: [Object],
read: [Function],
_consuming: true,
_idleTimeout: -1,
_idleNext: null,
_idlePrev: null,
_idleStart: 41897 },
connection:
TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: null,
npnProtocol: undefined,
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object],
_eventsCount: 10,
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: ‘test.salesforce.com’,
_readableState: [Object],
readable: false,
domain: null,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
destroyed: true,
_bytesDispatched: 250,
_sockname: null,
_pendingData: null,
_pendingEncoding: ‘’,
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
parser: null,
_httpMessage: [Object],
read: [Function],
_consuming: true,
_idleTimeout: -1,
_idleNext: null,
_idlePrev: null,
_idleStart: 41897 },
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: ‘1.1’,
complete: true,
headers:
{ date: ‘Tue, 01 Aug 2017 02:42:19 GMT’,
‘strict-transport-security’: ‘max-age=31536000; includeSubDomains’,
‘x-content-type-options’: ‘nosniff’,
‘x-xss-protection’: ‘1; mode=block’,
‘content-security-policy’: ‘referrer origin-when-cross-origin; upgrade-insecure-requests’,
‘set-cookie’: [Object],
expires: ‘Thu, 01 Jan 1970 00:00:00 GMT’,
‘transfer-encoding’: ‘chunked’,
connection: ‘close’ },
rawHeaders:
[ ‘Date’,
‘Tue, 01 Aug 2017 02:42:19 GMT’,
‘Strict-Transport-Security’,
‘max-age=31536000; includeSubDomains’,
‘X-Content-Type-Options’,
‘nosniff’,
‘X-XSS-Protection’,
‘1; mode=block’,
‘Content-Security-Policy’,
‘referrer origin-when-cross-origin; upgrade-insecure-requests’,
‘Set-Cookie’,
‘BrowserId=uopBZvoCQyKe7EHz6mpziA;Path=/;Domain=.salesforce.com;Expires=Sat, 30-Sep-2017 02:42:19 GMT’,
‘Expires’,
‘Thu, 01 Jan 1970 00:00:00 GMT’,
‘Transfer-Encoding’,
‘chunked’,
‘Connection’,
‘close’ ],
trailers: {},
rawTrailers: [],
upgrade: false,
url: ‘’,
method: null,
statusCode: 403,
statusMessage: ‘Forbidden’,
client:
TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: null,
npnProtocol: undefined,
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object],
_eventsCount: 10,
connecting: false,
_hadError: false,
_handle: null,
_parent: null,
_host: ‘test.salesforce.com’,
_readableState: [Object],
readable: false,
domain: null,
_maxListeners: undefined,
_writableState: [Object],
writable: false,
allowHalfOpen: false,
destroyed: true,
_bytesDispatched: 250,
_sockname: null,
_pendingData: null,
_pendingEncoding: ‘’,
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
parser: null,
_httpMessage: [Object],
read: [Function],
_consuming: true,
_idleTimeout: -1,
_idleNext: null,
_idlePrev: null,
_idleStart: 41897 },
_consuming: true,
_dumped: false,
req:
ClientRequest {
domain: null,
_events: [Object],
_eventsCount: 6,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: true,
upgrading: false,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedHeader: {},
_contentLength: 0,
_hasBody: true,
_trailer: ‘’,
finished: true,
_headerSent: true,
socket: [Object],
connection: [Object],
_header: ‘GET /services/oauth2/userinfo HTTP/1.1\r\nAuthorization: Bearer xxxxxxxxxxx\r\nhost: test.salesforce.com\r\naccept: application/json\r\nConnection: close\r\n\r\n’,
_headers: [Object],
_headerNames: [Object],
_onPendingData: null,
agent: [Object],
socketPath: undefined,
timeout: undefined,
method: ‘GET’,
path: ‘/services/oauth2/userinfo’,
_ended: true,
parser: null,
timeoutCb: [Function: emitTimeout],
res: [Circular] },
request:
Request {
domain: null,
_events: [Object],
_eventsCount: 5,
_maxListeners: undefined,
uri: [Object],
method: ‘GET’,
headers: [Object],
timeout: 30000,
readable: true,
writable: true,
explicitMethod: true,
_qs: [Object],
_auth: [Object],
_oauth: [Object],
_multipart: [Object],
_redirect: [Object],
_tunnel: [Object],
_rp_resolve: [Function: s],
_rp_reject: [Function: t],
_rp_promise: [Object],
_rp_callbackOrig: undefined,
callback: [Function],
_rp_options: [Object],
setHeader: [Function],
hasHeader: [Function],
getHeader: [Function],
removeHeader: [Function],
localAddress: undefined,
pool: {},
dests: [],
__isRequestRequest: true,
_callback: [Function: RP$callback],
proxy: null,
tunnel: true,
setHost: true,
originalCookieHeader: undefined,
_disableCookies: true,
_jar: undefined,
port: 443,
host: ‘test.salesforce.com’,
path: ‘/services/oauth2/userinfo’,
_json: true,
httpModule: [Object],
agentClass: [Object],
agent: [Object],
_started: true,
href: ‘https://test.salesforce.com/services/oauth2/userinfo’,
req: [Object],
ntick: true,
timeoutTimer: null,
response: [Circular],
originalHost: ‘test.salesforce.com’,
originalHostHeaderName: ‘host’,
responseContent: [Circular],
_destdata: true,
_ended: true,
_callbackCalled: true },
toJSON: [Function: responseToJSON],
caseless: Caseless { dict: [Object] },
read: [Function],
body: ‘Bad_OAuth_Token’ } }

In case success, the result value is:

{ sub: ‘https://test.salesforce.com/id/00D6300xxxxxxxxx/0056300xxxxxxxxx’,
user_id: ‘0056300000xxxxx’,
organization_id: ‘00D63000000xxxxxxx’,
preferred_username: ‘komodoxxxxxxx’,
nickname: ‘komodoxxxxxxx’,
name: ‘Thor1’,
email: ‘komodoxxxxxxx’,
email_verified: true,
family_name: ‘Thor1’,
zoneinfo: ‘America/Los_Angeles’,
photos:
{ picture: ‘https://xxxxxxxxxx.salesforce.com/img/userprofile/default_profile_xxxx.png’,
thumbnail: ‘https://xxxxxxxxxx.salesforce.com/img/userprofile/default_profile_xxxx.png’ },
profile: ‘https://xxxxxxxxxx.salesforce.com/0056300000xxxxx’,
picture: ‘https://xxxxxxxxxx.salesforce.com/img/userprofile/default_profile_xxxx.png’,
address: { country: ‘United States’ },
urls:
{ enterprise: ‘https://xxxxxxxxxx.salesforce.com/services/Soap/c/{version}/00xxxx’,
metadata: ‘https://xxxxxxxxxx.salesforce.com/services/Soap/m/{version}/00xxxx’,
partner: ‘https://xxxxxxxxxx.salesforce.com/services/Soap/u/{version}/00xxxx’,
rest: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/’,
sobjects: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/sobjects/’,
search: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/search/’,
query: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/query/’,
recent: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/recent/’,
tooling_soap: ‘https://xxxxxxxxxx.salesforce.com/services/Soap/T/{version}/00xxxx’,
tooling_rest: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/tooling/’,
profile: ‘https://xxxxxxxxxx.salesforce.com/0056300000xxxxxx’,
feeds: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/chatter/feeds’,
groups: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/chatter/groups’,
users: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/chatter/users’,
feed_items: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/chatter/feed-items’,
feed_elements: ‘https://xxxxxxxxxx.salesforce.com/services/data/v{version}/chatter/feed-elements’,
custom_domain: ‘https://xxxxxxxxxx.salesforce.com’ },
active: true,
user_type: ‘POWER_PARTNER’,
language: ‘en_US’,
locale: ‘en_US’,
utcOffset: -28800000,
updated_at: ‘2017-07-18T07:55:58.000+0000’,
is_app_installed: true }

Please let me know if you need more details.

Thanks.
Best regards.


#4

Where are you putting in your Salesforce credentials? That is a salesforce error returning you a 403 from their OAuth APi

I found this here:
https://developer.salesforce.com/forums/?id=906F000000099xhIAA


#5

Also, why are you parsing JSON in the custom JS? You should validate the JWT token given to you by the mobile client. See the cognito example here:


#6

Dear Ian,
Currently, we are using Salesforce Identity so we just send access_token only (sfData.access_token).

In another case, i still get the exception when calling the below code:

verifyIdentifier(req) {
return new Promise((resolve, reject) => {
reject(new Error(‘Not implemented!’));
});
}

So i think this issue is not related to Salesforce.

Please let me know your opinions.

Thanks.
Best regards.


#7

@komodo Please share the working code that takes a Salesforce token, sends it to their API, and returns that success response you pasted without Realm Object Server. Also, please share your configuration.yml where you configure your custom authentication.


#8

Dear Ian,

Please take a look the following example which is using redux-sagas:

_We log into Salesforce and get access token. Salesforce document:
https://developer.salesforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com

_After that we use the access token to query user info:


export function * startUserSession (loginSuccessAction) {
const {authorization} = loginSuccessAction
const sfApi = new SalesforceApi(authorization)
const response = yield apply(sfApi, sfApi.currentUser)
yield put(LoginActionCreators.currentUserSuccess(response.data))
yield put(NavigationActions.navigate({
routeName: ‘HomeScreen’
}))
}


export class SalesforceApi {
constructor (authorizationToken) {
this.authorizationToken = authorizationToken
const {accessToken} = this.authorizationToken
this.apiClient = apisauce.create({
baseURL: salesforce_communityUrl_xxxxxxxx,
headers: {
‘Authorization’: Bearer ${accessToken},
‘Cache-Control’: ‘no-cache’
},
timeout: 10000
})
}
currentUser () {
return
this.apiClient.get(/services/data/v39.0/connect/communities/communityIdxxxxxxxxx/chatter/users/me)
}
}

And here is content of configuration.yml, nothing special, just follow realm documents
https://realm.io/docs/realm-object-server/#custom-authentication

Salesforce

custom/SFAuth:
  implementation: SFAuth.js
  include_path: /Users/xxxxxx/.realm/auth

Thank you so much.

Best regards.


#9

@komodo I do not believe it is on the ROS side - try returning promise.resolve “abc” or some other string. Does it work?


#10

Dear Ian,
I tried that and it doesn’t work.

Example:

verifyIdentifier(req) {
return new Promise((resolve, reject) => {
reject(new Error(‘Not implemented!’));
});
}

Thanks.
Best regards.


#11

Can you share the entire code from SFAuth.js?


#12

@komodo I meant like this:

 verifyIdentifier(req) {
	return Promise.resolve("abcefgtesttest")
}

#13

Dear Adam,
Here is content of SFAuth.js:

module.exports = function (deps) {
return class SFAuthProvider extends deps.BaseAuthProvider {
static get name () {
return ‘custom/SFAuth’;
}
static get defaultOptions () {
return {
server: ‘https://xxxxxxxxxxxxxxxxxxxxxx.force.com
}
}
constructor(name, options, requestPromise) {
super(name, options, requestPromise);
this.httpMethod = ‘GET’;
}
verifyIdentifier(req) {
const jsonData = req.body.data;
var sfData = JSON.parse(jsonData);
console.log(sfData)
const httpOptions = {
uri: sfData.id_url,
method: this.httpMethod,
json: true,
headers: {
‘Authorization’: 'Bearer ’ + sfData.access_token
},
timeout: 30000
};
return this.request(httpOptions).catch((err) => {
console.log(err)
throw new deps.problem.HttpProblem.Unauthorized({
detail: ${err.toString()}
})
}).then((result) => {
console.log(result)
return result.user_id
})
}
}
}


#14

Dear Ian,
There is no problem if using your code :slight_smile:

The issue happens when there is an error only.

Thank you so much.

Best regards,
LNPQuang


#15

@komodo Where are your require statements for the npm packages you would pull in for this script?


#16

Dear Ian,
There is no ‘require’ statement. Which package would you like to ‘require’?
I used the example code from: https://realm.io/docs/realm-object-server/#custom-authentication

Please let me know your opinions.
Thanks.
Best regards.


#17

@komodo probably express and body-parser - your code needs to be able to run on the server like node myAuth.js


#18

Dear Ian,
I tried all your suggestions but still failed. So we are trying to work around :frowning:

Thanks.
Best regards.


#19

@komodo Please email me at [email protected] with a test account and all your information needed to query your API and I will build it for you.


#20

Dear Ian,
Thank you so much. I will email you all information for testing.

Thanks.
Best regards.