By: Ha Ro user 26 Jun 2020 at 12:27 p.m. CDT

2 Responses
Ha Ro gravatar
Desired: User lands on Gluu login page and clicks the "External Providers: Discord" link. User prompted to authorize app by discord.com website. User authorizes app, app is added to the Discord user account's list of authorized apps. User is logged into gluu and Discord. Can see it working on 4.1 here: https://p1.rpgr.org But need it working on 3.1.6. With help from the wonderful folks at Centroxy, we were able to get this working for Gluu 4.1, but for our production environment we need it working for Gluu 3.1.6. We hope to migrate to 4.1 in a few months, but we must get this working ASAP on 3.1.6. As per here: https://support.gluu.org/access-management/8399/anyone-tried-implementing-gluu-and-discord-chat-server-oauth2-or-other-methods/#at61462 But I was asked for trying to get this working on 3.1.6 to create a separate ticket here. I tried using the info from the 4.1 setup trying to adapt it backwards to 3.1.6 but it isn't quite working. Hopefully folks here can point me in the right direction to getting this working. Thanks! On Ubunty 16.04 LTS, Gluu 3.1.6. Config comparison information and logs below: Here is the discord.js strategy from the 4.1 and 3.6.1 install and related information. Gluu 4.1 test server: https://p1.rpgr.org (basically works though needs some refinement) GLuu 3.1.6 test server: https://devau.thefantasy.network (not working, just trying to get working at least as well as the 4.1 version). # Gluu 4.1 Passport Discord Strategy discord.js :/opt/gluu/node/passport/server/mappings# cat discord.js ``` module.exports = profile =&gt; { return { uid: profile.username || profile.id, mail: profile.email, cn: profile.displayName || profile.username, displayName: profile.displayName || profile.username, givenName: profile.username, sn: profile.username } } ``` # Gluu 3.1.6 discord.js:/opt/gluu/node/passport/server/auth# cat configureStrategies.js ``` var DiscordStrategy = require('./discord'); var FacebookStrategy = require('./facebook'); var GitHubStrategy = require('./github'); var GoogleStrategy = require('./google'); var LinkedinStrategy = require('./linkedin'); var TumblrStrategy = require('./tumblr'); var TwitterStrategy = require('./twitter'); var YahooStrategy = require('./yahoo'); var DropboxOAuth2Strategy = require('./dropbox'); var OIDCStrategy = require('./openidconnect') var SamlStrategy = require("./saml"); var logger = require("../utils/logger") ``` ``` exports.setConfigurations = function(data){ SamlStrategy.setCredentials(); if (data &amp;&amp; data.passportStrategies) { //DiscordStrategy added by Hawke if (data.passportStrategies.discord) { logger.log2('info', 'Discord Strategy details received') DiscordStrategy.setCredentials(data.passportStrategies.discord) } //FacebookStrategy if (data.passportStrategies.facebook) { logger.log2('info', 'Facebook Strategy details received') FacebookStrategy.setCredentials(data.passportStrategies.facebook) } //GitHubStrategy if (data.passportStrategies.github) { logger.log2('info', 'Github Strategy details received') GitHubStrategy.setCredentials(data.passportStrategies.github) } //DropboxOAuth2Strategy if (data.passportStrategies.dropbox) { logger.log2('info', 'DropboxOAuth2 Strategy details received') DropboxOAuth2Strategy.setCredentials(data.passportStrategies.dropbox) } //GoogleStrategy if (data.passportStrategies.google) { logger.log2('info', 'Google Strategy details received') GoogleStrategy.setCredentials(data.passportStrategies.google) } //LinkedinStrategy if (data.passportStrategies.linkedin) { logger.log2('info', 'LinkedIn Strategy details received') LinkedinStrategy.setCredentials(data.passportStrategies.linkedin) } //TumblrStrategy if (data.passportStrategies.tumblr) { logger.log2('info', 'Tumblr Strategy details received') TumblrStrategy.setCredentials(data.passportStrategies.tumblr) } //TwitterStrategy if (data.passportStrategies.twitter) { logger.log2('info', 'Twitter Strategy details received') TwitterStrategy.setCredentials(data.passportStrategies.twitter) } //YahooStrategy if (data.passportStrategies.yahoo) { logger.log2('info', 'Yahoo Strategy details received') YahooStrategy.setCredentials(data.passportStrategies.yahoo) } //OIDCStrategy if (data.passportStrategies.openidconnect) { logger.log2('info', 'OIDC details received') OIDCStrategy.setCredentials(data.passportStrategies.openidconnect) } //SamlStrategy if (data.passportStrategies.saml) { logger.log2('info', 'Saml Strategy details received') } } else { logger.log2('error', 'Error in getting data: %s', JSON.stringify(err)) } }; ``` ``` Attempted replication in 3.1.6 formatting: /opt/gluu/node/passport/server/auth# cat discord.js var passport = require('passport'); var DiscordStrategy = require('passport-discord').Strategy; var setCredentials = function(credentials) { var callbackURL = global.applicationHost.concat("/passport/auth/discord/callback"); passport.use(new DiscordStrategy({ clientID: credentials.clientID, clientSecret: credentials.clientSecret, callbackURL: callbackURL, // enableProof: true, passReqToCallback: true // profileFields: ['id', 'name', 'displayName', 'email'] profileFields: ['id', 'name', 'displayName', 'email'] }, function(accessToken, refreshToken, profile, done) { var userProfile = { // id: profile._json.id || "", // id: profile.username || profile.id, id: profile.username || "", // uid: profile.username || profile.id, // name: profile.displayName || "", // name: profile.displayName || profile.username, name: profile.displayName || "", // username: profile.username || profile._json.id, // username: profile.username || "", username: profile.username || "", // email: profile._json.email || "", // email: profile.email || "", email: profile.email || "", // givenName: profile._json.first_name || "", givenName: profile.username || "", // familyName: profile._json.last_name || "", provider: "discord" }; return done(null, userProfile); } )); }; module.exports = { passport: passport, setCredentials: setCredentials }; //module.exports = profile =&gt; { // return { // uid: profile.username || profile.id, // mail: profile.email, // cn: profile.displayName || profile.username, // displayName: profile.displayName || profile.username, // givenName: profile.username, // sn: profile.username // } //} ``` # Gluu 4.1: extra-passport-params.js: /opt/gluu/node/passport/server# cat extra-passport-params.js ``` const fs = require('fs'), R = require('ramda') //Extra params supplied per strategy //They are not set via oxTrust to keep complexity manageable. These params are not expected to change: admins probably will never have to edit the below //This is wrapped in a function so params is not evaluated upon module load, only at first usage const params = R.once(() =&gt; [ { strategy: 'passport-saml', passportAuthnParams: {}, options: { validateInResponseTo: true, requestIdExpirationPeriodMs: 3600000, decryptionPvk: fs.readFileSync(global.config.spTLSKey, 'utf-8'), decryptionCert: fs.readFileSync(global.config.spTLSCert, 'utf-8') } }, { strategy: 'passport-oxd', passportAuthnParams: { scope: ['openid', 'email', 'profile'] }, options: {} }, { strategy: 'passport-dropbox-oauth2', passportAuthnParams: {}, options: { apiVersion: '2' } }, { strategy: 'passport-facebook', passportAuthnParams: { scope: ['email'] }, options: { profileFields: ['id', 'displayName', 'name', 'emails'], enableProof: true } }, { strategy: 'passport-discord', passportAuthnParams: {}, options: { scope: ['identify', 'email'], state: true } }, { strategy: 'passport-github', passportAuthnParams: { scope: ['user'] }, options: {} }, { strategy: 'passport-google-oauth2', passportAuthnParams: { scope: ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'] }, options: {} }, { strategy: '@sokratis/passport-linkedin-oauth2', passportAuthnParams: {}, options: { scope: ['r_emailaddress', 'r_liteprofile'], state: true } }, { strategy: 'passport-twitter', passportAuthnParams: {}, options: { includeEmail: true } }, { strategy: 'passport-windowslive', passportAuthnParams: { //TODO: verify scope: ['wl.signin', 'wl.basic'] }, options: {} } ]) function get(strategyId, paramName) { //Select the (only) item matching let obj = R.find(R.propEq('strategy', strategyId), params()) return R.defaultTo({}, R.prop(paramName, obj)) } module.exports = { get: get } ``` # Gluu 3.1.6 configureStrategies.js :/opt/gluu/node/passport/server/auth# cat configureStrategies.js ``` var DiscordStrategy = require('./discord'); var FacebookStrategy = require('./facebook'); var GitHubStrategy = require('./github'); var GoogleStrategy = require('./google'); var LinkedinStrategy = require('./linkedin'); var TumblrStrategy = require('./tumblr'); var TwitterStrategy = require('./twitter'); var YahooStrategy = require('./yahoo'); var DropboxOAuth2Strategy = require('./dropbox'); var OIDCStrategy = require('./openidconnect') var SamlStrategy = require("./saml"); var logger = require("../utils/logger") exports.setConfigurations = function(data){ SamlStrategy.setCredentials(); if (data &amp;&amp; data.passportStrategies) { //DiscordStrategy added by Hawke if (data.passportStrategies.discord) { logger.log2('info', 'Discord Strategy details received') DiscordStrategy.setCredentials(data.passportStrategies.discord) } //FacebookStrategy if (data.passportStrategies.facebook) { logger.log2('info', 'Facebook Strategy details received') FacebookStrategy.setCredentials(data.passportStrategies.facebook) } //GitHubStrategy if (data.passportStrategies.github) { logger.log2('info', 'Github Strategy details received') GitHubStrategy.setCredentials(data.passportStrategies.github) } //DropboxOAuth2Strategy if (data.passportStrategies.dropbox) { logger.log2('info', 'DropboxOAuth2 Strategy details received') DropboxOAuth2Strategy.setCredentials(data.passportStrategies.dropbox) } //GoogleStrategy if (data.passportStrategies.google) { logger.log2('info', 'Google Strategy details received') GoogleStrategy.setCredentials(data.passportStrategies.google) } //LinkedinStrategy if (data.passportStrategies.linkedin) { logger.log2('info', 'LinkedIn Strategy details received') LinkedinStrategy.setCredentials(data.passportStrategies.linkedin) } //TumblrStrategy if (data.passportStrategies.tumblr) { logger.log2('info', 'Tumblr Strategy details received') TumblrStrategy.setCredentials(data.passportStrategies.tumblr) } //TwitterStrategy if (data.passportStrategies.twitter) { logger.log2('info', 'Twitter Strategy details received') TwitterStrategy.setCredentials(data.passportStrategies.twitter) } //YahooStrategy if (data.passportStrategies.yahoo) { logger.log2('info', 'Yahoo Strategy details received') YahooStrategy.setCredentials(data.passportStrategies.yahoo) } //OIDCStrategy if (data.passportStrategies.openidconnect) { logger.log2('info', 'OIDC details received') OIDCStrategy.setCredentials(data.passportStrategies.openidconnect) } //SamlStrategy if (data.passportStrategies.saml) { logger.log2('info', 'Saml Strategy details received') } } else { logger.log2('error', 'Error in getting data: %s', JSON.stringify(err)) } }; ``` # Gluu 3.1.6 index.js Snippet: root@localhost:/opt/gluu/node/passport/server/routes# grep discord * ``` var passportDiscord = require('../auth/discord').passport; case 'discord': //=============discord added by hawke ========== router.get('/auth/discord/callback', passportDiscord.authenticate('discord', { router.get('/auth/discord/:token', passportDiscord.authenticate('discord', { ``` Full file: /opt/gluu/node/passport/server/routes# cat index.js ``` var express = require('express'); var router = express.Router(); var jwt = require('jsonwebtoken'); var util = require('util') var passportLinkedIn = require('../auth/linkedin').passport; var passportGithub = require('../auth/github').passport; var passportTwitter = require('../auth/twitter').passport; var passportDiscord = require('../auth/discord').passport; var passportFacebook = require('../auth/facebook').passport; var passportTumblr = require('../auth/tumblr').passport; var passportYahoo = require('../auth/yahoo').passport; var passportGoogle = require('../auth/google').passport; var passportWindowsLive = require('../auth/windowslive').passport; var passportDropbox = require('../auth/dropbox').passport; var passportSAML = require('../auth/saml').passport; var passportOIDC = require('../auth/openidconnect').passport var fs = require('fs'); var uuid = require('uuid'); var logger = require("../utils/logger") var misc = require('../utils/misc') var openid = require('../openid/openid') var validateToken = function (req, res, next) { var token = req.body &amp;&amp; req.body.token || req.params &amp;&amp; req.params.token || req.headers['x-access-token']; if (token) { // verifies secret and checks expiration of token jwt.verify(token, global.applicationSecretKey, function (err, decoded) { if (err) { return res.json({ success: false, message: 'Failed to authenticate token.' }); } else { // if everything is good, save to request for use in other routes req.decoded = decoded; return next(); } }); } else { // if there is no token, return an error return res.redirect(global.config.applicationStartpoint + '?failure=No token provided'); } }; var casaCallback = function (req, res) { var provider = req.params.provider res.cookie('casa-' + provider, req.decoded.exp, { httpOnly: true, maxAge: 120000, //2min expiration secure: true }) var obj switch (provider) { case 'github': obj = passportGithub break case 'twitter': obj = passportTwitter break case 'discord': obj = passportDiscord break case 'facebook': obj = passportFacebook break case 'tumblr': obj = passportTumblr break case 'yahoo': obj = passportYahoo break case 'google': obj = passportGoogle break case 'windowslive': obj = passportWindowsLive break case 'dropbox': obj = passportDropbox break case 'openidconnect': obj = passportOIDC break } if (!obj &amp;&amp; (provider in global.saml_config)) { obj = passportSAML } var lurl = '/casa/rest/pl/account-linking/idp-linking' if (!obj) { res.redirect(util.format('%s?failure=Provider %s not recognized in passport-casa mapping', lurl, provider)) } else { logger.log2('verbose', 'At casaCallback, proceeding with linking procedure for provider %s', provider) obj.authenticate(provider, { failureRedirect: util.format('%s?failure=An error occurred triggering authentication for %s', lurl, provider) } )(req,res) } } var callbackResponse = function (req, res) { if (!req.user) { return res.redirect(global.config.applicationStartpoint + '?failure=Unauthorized'); } var provider = req.params.providerKey || req.user.provider var postUrl if (req.cookies['casa-' + provider]) { postUrl = '/casa/rest/pl/account-linking/idp-linking/' + encodeURIComponent(provider) } else { postUrl = global.config.applicationEndpoint } var subject = req.user.id logger.log2('info', 'User authenticated with userid "%s" and strategy "%s"', subject, provider) var now = new Date().getTime() var jwt = misc.getJWT({ iss: postUrl, sub: subject, aud: global.config.clientId, jti: uuid(), exp: now / 1000 + 30, iat: now, data: req.user }) logger.log2('debug', 'Preparing to send user data to: %s with JWT=%s', postUrl, jwt) var response_body = ` &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&gt; &lt;head&gt; &lt;/head&gt; &lt;body onload="document.forms[0].submit()"&gt; &lt;noscript&gt; &lt;p&gt; <strong>Note:</strong> Since your browser does not support JavaScript, you must press the Continue button once to proceed. &lt;/p&gt; &lt;/noscript&gt; &lt;form action="${postUrl}" method="post"&gt; &lt;div&gt; &lt;input type="hidden" name="user" value="${jwt}"/&gt; &lt;noscript&gt; &lt;input type="submit" value="Continue"/&gt; &lt;/noscript&gt; &lt;/div&gt; &lt;/form&gt; &lt;/body&gt; &lt;/html&gt; ` res.set('content-type', 'text/html;charset=UTF-8'); return res.send(response_body); }; var callbackAuthzResponse = function (req, res) { logger.log2('verbose', "callbackAuthzResponse. Entry point") if (!req.user) { return res.redirect(global.config.applicationStartpoint + '?failure=Unauthorized'); } var provider = req.user.providerKey var user = req.user var subject = user.id logger.log2('info', 'User authenticated with userid "%s" and strategy "%s"', subject, provider) logger.log2('verbose', 'callbackAuthzResponse. Full req is\n%s', util.inspect(req, {showHidden: false, depth: 2})) var idp_initiated_config = global.saml_idp_init_config[provider] logger.log2('verbose', 'Using inboung IDP config: %s', JSON.stringify(idp_initiated_config)) if (idp_initiated_config) { client = idp_initiated_config['openid_client'] authorization_params = idp_initiated_config['authorization_params'] // Cache authorization_endpoint authorization_endpoint = undefined if (idp_initiated_config[provider]) { authorization_endpoint = idp_initiated_config[provider] logger.log2('debug', 'Get cached authorization_endpoint: %s', authorization_endpoint) redirectToAuthorizationEndpoint(res, client, authorization_endpoint, authorization_params, user) } else { openid.getAuthorizationEndpoint(client['server_uri']) .then(authorization_endpoint =&gt; { logger.log2('debug', 'Get authorization_endpoint: %s', authorization_endpoint) idp_initiated_config[provider] = authorization_endpoint redirectToAuthorizationEndpoint(res, client, authorization_endpoint, authorization_params, user) }) } } else { return res.redirect(util.format('%s?failure=Unknown IDP %s or service provider %s', global.config.applicationStartpoint, provider, "")) } }; function redirectToAuthorizationEndpoint(res, client, authorization_endpoint, authorization_params, user) { logger.log2('debug', 'Call to redirectToAuthorizationEndpoint') var subject = user.id var now = new Date().getTime() var jwt = misc.getJWT({ iss: client['server_uri'], sub: subject, aud: authorization_params['client_id'], jti: uuid(), exp: now / 1000 + 30, iat: now, data: user }) logger.log2('debug', 'Preparing to send authorization request with user data to: %s with JWT=%s', authorization_endpoint, jwt) authorization_params_cloned = JSON.parse(JSON.stringify(authorization_params)) authorization_params_cloned['state'] = jwt authorization_url = openid.getAuthorizationUrl(authorization_endpoint, authorization_params_cloned) res.set('content-type', 'text/html;charset=UTF-8'); return res.redirect(authorization_url); } router.get('/', function (req, res, next) { res.render('index', { title: 'Node-Passport' }); }); router.get('/login', function (req, res, next) { res.redirect(global.config.applicationStartpoint + '?failure=An error occurred'); }); router.get('/casa/:provider/:token', validateToken, casaCallback) //=================== linkedin ================= router.get('/auth/linkedin/callback', passportLinkedIn.authenticate('linkedin', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/linkedin/:token', validateToken, passportLinkedIn.authenticate('linkedin')); //===================== github ================= router.get('/auth/github/callback', passportGithub.authenticate('github', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/github/:token', validateToken, passportGithub.authenticate('github', { scope: ['user:email'] })); //==================== twitter ================= router.use('/auth/twitter/callback', passportTwitter.authenticate('twitter', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/twitter/:token', validateToken, passportTwitter.authenticate('twitter')); //=============discord added by hawke ========== router.get('/auth/discord/callback', passportDiscord.authenticate('discord', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/discord/:token', validateToken, passportDiscord.authenticate('discord', { scope: ['identify', 'email'] })); //==================== facebook ================ router.get('/auth/facebook/callback', passportFacebook.authenticate('facebook', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/facebook/:token', validateToken, passportFacebook.authenticate('facebook', { scope: ['email'] })); //===================== tumblr ================= router.get('/auth/tumblr/callback', passportTumblr.authenticate('tumblr', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/tumblr/:token', validateToken, passportTumblr.authenticate('tumblr')); //===================== yahoo ================= router.get('/auth/yahoo/callback', passportYahoo.authenticate('yahoo', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/yahoo/:token', validateToken, passportYahoo.authenticate('yahoo')); //===================== google ================= router.get('/auth/google/callback', passportGoogle.authenticate('google', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/google/:token', validateToken, passportGoogle.authenticate('google', { scope: ['profile', 'email'] })); //================== windowslive =============== router.get('/auth/windowslive/callback', passportWindowsLive.authenticate('windowslive', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/windowslive/:token', validateToken, passportWindowsLive.authenticate('windowslive')); //================== dropbox ================== router.get('/auth/dropbox/callback', passportDropbox.authenticate('dropbox-oauth2', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/dropbox/:token', validateToken, passportDropbox.authenticate('dropbox-oauth2')); //=================== OIDC =================== router.get('/auth/openidconnect/callback', passportOIDC.authenticate('openidconnect', { failureRedirect: '/passport/login' }), callbackResponse); router.get('/auth/openidconnect/:token', validateToken, passportOIDC.authenticate('openidconnect')) //===================saml ==================== var entitiesJSON = global.saml_config; for (key in entitiesJSON) { if (entitiesJSON[key].cert &amp;&amp; entitiesJSON[key].cert.length &gt; 5 &amp;&amp; entitiesJSON[key].enable.match("true")) { router.post('/auth/saml/' + key + '/callback', passportSAML.authenticate(key, { failureRedirect: '/passport/login' }), callbackResponse); router.post('/auth/saml/' + key + '/callback/inbound', passportSAML.authenticate(key, { failureRedirect: '/passport/login' }), callbackAuthzResponse); router.get('/auth/saml/' + key + '/:token', validateToken, passportSAML.authenticate(key)); } else { router.get('/auth/saml/' + key + '/:token', validateToken, function (req, res) { err = { message: "cert param is required to validate signature of saml assertions response" }; logger.log2('error', 'Cert Error: %s', JSON.stringify(err)) res.status(400).send("Internal Error"); }); } } router.get('/auth/meta/idp/:idp', function (req, res) { var idp = req.params.idp; logger.log2('verbose', 'Metadata request for %s', idp); fs.readFile(__dirname + '/../idp-metadata/' + idp + '.xml', (e, data) =&gt; { if (e) { res.status(404).send("Internal Error") } else { res.status(200).set('Content-Type', 'text/xml').send(String(data)) } }) }); //======== catch 404 and forward to login ======== router.all('/*', function (req, res, next) { var err = new Error('Not Found'); err.status = 404; res.redirect(global.config.applicationStartpoint + '?failure=The requested resource does not exists!'); }); module.exports = router; ``` # Log output for GLuu 3.1.6 server /opt/gluu/jetty/oxauth/logs# tail -f * **User lands on the Gluu login page:** ``` 2020-06-26 14:05:00,392 INFO [qtp804611486-18] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. prepareForStep called 1 2020-06-26 14:05:00,394 INFO [qtp804611486-18] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. parseProviderConfigs. Adding social providers ==&gt; oxauth.log &lt;== 2020-06-26 14:05:00,395 INFO [qtp804611486-18] [org.xdi.oxauth.service.AppInitializer] (AppInitializer.java:330) - Created ldapEntryManager:org.gluu.site.ldap.persistence.LdapEntryManager@2f582dd4 with provider org.xdi.service.ldap.LdapConnectionService@7f256398 ==&gt; 2020_06_26.jetty.log &lt;== 2020-06-26 14:05:00,395 INFO [qtp804611486-18] [org.xdi.oxauth.service.AppInitializer] (AppInitializer.java:330) - Created ldapEntryManager:org.gluu.site.ldap.persistence.LdapEntryManager@2f582dd4 with provider org.xdi.service.ldap.LdapConnectionService@7f256398 ==&gt; oxauth_script.log &lt;== 2020-06-26 14:05:00,399 INFO [qtp804611486-18] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. prepareForStep. A page to manually select an identity provider will be shown 2020-06-26 14:05:00,399 INFO [qtp804611486-18] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called ``` **User clicks the Discord link** ``` 2020-06-26 14:05:04,956 INFO [qtp804611486-11] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. authenticate called 1 2020-06-26 14:05:04,957 INFO [qtp804611486-11] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. authenticate for step 1. Retrying step 1 ==&gt; oxauth.log &lt;== 2020-06-26 14:05:04,959 INFO [qtp804611486-11] [org.xdi.oxauth.auth.Authenticator] (Authenticator.java:345) - Authentication reset to step : '1' ==&gt; 2020_06_26.jetty.log &lt;== 2020-06-26 14:05:04,959 INFO [qtp804611486-11] [org.xdi.oxauth.auth.Authenticator] (Authenticator.java:345) - Authentication reset to step : '1' ==&gt; oxauth_script.log &lt;== 2020-06-26 14:05:04,961 INFO [qtp804611486-11] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called 2020-06-26 14:05:04,961 INFO [qtp804611486-11] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getCountAuthenticationSteps called 2020-06-26 14:05:04,962 INFO [qtp804611486-11] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called 2020-06-26 14:05:05,065 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. prepareForStep called 1 2020-06-26 14:05:05,066 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. parseProviderConfigs. Adding social providers ==&gt; oxauth.log &lt;== 2020-06-26 14:05:05,068 INFO [qtp804611486-14] [org.xdi.oxauth.service.AppInitializer] (AppInitializer.java:330) - Created ldapEntryManager:org.gluu.site.ldap.persistence.LdapEntryManager@2f8f1d27 with provider org.xdi.service.ldap.LdapConnectionService@7f256398 ==&gt; 2020_06_26.jetty.log &lt;== 2020-06-26 14:05:05,068 INFO [qtp804611486-14] [org.xdi.oxauth.service.AppInitializer] (AppInitializer.java:330) - Created ldapEntryManager:org.gluu.site.ldap.persistence.LdapEntryManager@2f8f1d27 with provider org.xdi.service.ldap.LdapConnectionService@7f256398 ==&gt; oxauth_script.log &lt;== 2020-06-26 14:05:05,073 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getPassportRedirectUrl. Obtaining token from passport at https://devau.thefantasy.network/passport/token 2020-06-26 14:05:05,140 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getPassportRedirectUrl. Response was 503 2020-06-26 14:05:05,141 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getPassportRedirectUrl. Error building redirect URL: 2020-06-26 14:05:05,141 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - expected string or buffer, but got &lt;type 'NoneType'&gt; 2020-06-26 14:05:05,142 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. prepareForStep. A page to manually select an identity provider will be shown 2020-06-26 14:05:05,146 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called ``` Additional logs: /opt/gluu/jetty/oxauth/logs# tail -f * When click the Discord link on the Gluu login page (which just comes back to the GLuu login page rather than the Discord Auth/login prompt): ``` ==&gt; oxauth_script.log &lt;== 2020-06-26 15:21:34,918 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. authenticate called 1 2020-06-26 15:21:34,920 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. authenticate for step 1. Retrying step 1 ==&gt; oxauth.log &lt;== 2020-06-26 15:21:34,922 INFO [qtp804611486-14] [org.xdi.oxauth.auth.Authenticator] (Authenticator.java:345) - Authentication reset to step : '1' ==&gt; 2020_06_26.jetty.log &lt;== 2020-06-26 15:21:34,922 INFO [qtp804611486-14] [org.xdi.oxauth.auth.Authenticator] (Authenticator.java:345) - Authentication reset to step : '1' ==&gt; oxauth_script.log &lt;== 2020-06-26 15:21:34,923 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called 2020-06-26 15:21:34,924 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getCountAuthenticationSteps called 2020-06-26 15:21:34,925 INFO [qtp804611486-14] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called 2020-06-26 15:21:35,022 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. prepareForStep called 1 2020-06-26 15:21:35,024 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. parseProviderConfigs. Adding social providers ==&gt; oxauth.log &lt;== 2020-06-26 15:21:35,025 INFO [qtp804611486-15] [org.xdi.oxauth.service.AppInitializer] (AppInitializer.java:330) - Created ldapEntryManager:org.gluu.site.ldap.persistence.LdapEntryManager@2124e51a with provider org.xdi.service.ldap.LdapConnectionService@53c4b36b ==&gt; 2020_06_26.jetty.log &lt;== 2020-06-26 15:21:35,025 INFO [qtp804611486-15] [org.xdi.oxauth.service.AppInitializer] (AppInitializer.java:330) - Created ldapEntryManager:org.gluu.site.ldap.persistence.LdapEntryManager@2124e51a with provider org.xdi.service.ldap.LdapConnectionService@53c4b36b ==&gt; oxauth_script.log &lt;== 2020-06-26 15:21:35,032 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getPassportRedirectUrl. Obtaining token from passport at https://devau.thefantasy.network/passport/token 2020-06-26 15:21:35,091 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getPassportRedirectUrl. Response was 503 2020-06-26 15:21:35,092 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getPassportRedirectUrl. Error building redirect URL: 2020-06-26 15:21:35,093 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - expected string or buffer, but got &lt;type 'NoneType'&gt; 2020-06-26 15:21:35,093 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. prepareForStep. A page to manually select an identity provider will be shown 2020-06-26 15:21:35,093 INFO [qtp804611486-15] [org.xdi.service.PythonService$PythonLoggerOutputStream] (PythonService.java:239) - Passport. getExtraParametersForStep called ``` Found this other file that looks like also needs to be edited? So added the Discord listing: /opt/gluu/node/passport/server/views# cat index.html ``` {% extends 'layout.html' %} {% block title %}{% endblock %} {% block content %} &lt;div class="container"&gt; &lt;h1&gt;{{ title }}&lt;/h1&gt; &lt;p&gt;Welcome! Please Login.&lt;/p&gt; &lt;hr&gt;&lt;br&gt; <a href="/auth/linkedin/passtoken">LinkedIn</a> <a href="/auth/github/passtoken">Github</a> <a href="/auth/twitter/passtoken">Twitter</a> <a href="/auth/google/passtoken">Google</a> <a href="/auth/discord/passtoken">Discord</a> <a href="/auth/facebook/passtoken">Facebook</a> <a href="/auth/tumblr/passtoken">Tumblr</a> <a href="/auth/yahoo/passtoken">Yahoo</a> &lt;/div&gt; {% endblock %} ``` also update section of login.xhtml in /opt/gluu/jetty/oxauth/custom/pages --snippet--``` &lt;div class="button_social"&gt; <ul> <li><a href="#"><i></i> Sign In with Discord</a></li> <li><a href="#"><i></i> Sign In with Facebook</a></li> <li><a href="#"><i></i> Sign In with Twitter</a></li> <li><a href="#"><i></i> Sign In with Google+</a></li> <li><a href="#"><i></i> Sign In with Linkedin</a></li> </ul> &lt;p&gt;or Login with&lt;/p&gt; ``` --snippet-- That did _not_ get it working, but another piece of the puzzle to include I guess. Here is another version I tried of the discord.js for 3.1.6: var passport = require('passport'); var DiscordStrategy = require('passport-discord').Strategy; var setCredentials = function(credentials) { var callbackURL = global.applicationHost.concat("/passport/auth/discord/callback"); passport.use(new DiscordStrategy({ clientID: credentials.clientID, clientSecret: credentials.clientSecret, callbackURL: callbackURL, passReqToCallback: true profileFields: ['id', 'name', 'displayName', 'email'] }, function(accessToken, refreshToken, profile, done) { var userProfile = { id: profile.username || profile.id || "", // cn: profile.displayName || profile.username || "", // displayName: profile.displayName || proile.username || "", name: profile.displayName || profile.username || "", username: profile.username || "", email: profile.email || "", givenName: profile.username || "", // sn: profile.username || "", familyName: profile.username || "", provider: "discord" }; return done(null, userProfile); } )); }; module.exports = { passport: passport, setCredentials: setCredentials }; //module.exports = profile =&gt; { // return { // uid: profile.username || profile.id, // mail: profile.email, // cn: profile.displayName || profile.username, // displayName: profile.displayName || profile.username, // givenName: profile.username, // sn: profile.username // } //} Still not working. Any ideas what else I could try to get this working in 3.1.6? Thanks!

By Jose Gonzalez staff 26 Jun 2020 at 4:29 p.m. CDT

Jose Gonzalez gravatar
Hi, Very nice ticket description.... You forgot the probably most relevant log here though. Please share `/opt/gluu/node/passport/server/logs/passport.log`

By Ha Ro user 26 Jun 2020 at 6:22 p.m. CDT

Ha Ro gravatar
Sorry didnt include that log becuase server was running in "info" level and so wasn't showing anything in the log. I tweaked it to debug and I found two problems with the server. Someone had once again reverted the hostname to localhost ((volunteers working on this, so things can be a little frustratingly chaotic)). I locked that in to survive reboot in the VM (hopefully that gluu dev box isn't too corrupted by the hostname change I don't know how long they were running it that way). Fortunately not production. AFter that I was able to find there was a missing comma in my tweak of the discord.js. This discord.js works in 3.1.6 at the most basic level with Gluu + Discord: ``` /opt/gluu/node/passport/server/auth# cat discord.js var passport = require('passport'); var DiscordStrategy = require('passport-discord').Strategy; var setCredentials = function(credentials) { var callbackURL = global.applicationHost.concat("/passport/auth/discord/callback"); passport.use(new DiscordStrategy({ clientID: credentials.clientID, clientSecret: credentials.clientSecret, callbackURL: callbackURL, profileFields: ['id', 'name', 'displayName', 'email'] }, function(accessToken, refreshToken, profile, done) { var userProfile = { id: profile.username || profile.id || "", name: profile.displayName || profile.username || "", username: profile.username || "", email: profile.email || "", givenName: profile.username || "", familyName: profile.username || "", provider: "discord" }; return done(null, userProfile); } )); }; module.exports = { passport: passport, setCredentials: setCredentials }; ``` Yay! So I will close this out, but hopefully this information will help any others trying to get Discord working as well.