2
0
Эх сурвалжийг харах

feat: social login providers with dynamic instances

NGPixel 4 жил өмнө
parent
commit
32d67adee1
28 өөрчлөгдсөн 147 нэмэгдсэн , 107 устгасан
  1. 2 1
      client/components/admin/admin-users-edit.vue
  2. 4 1
      client/components/admin/admin-users.vue
  3. 1 1
      client/components/profile/profile.vue
  4. 2 2
      dev/build-arm/Dockerfile
  5. 3 3
      dev/build/Dockerfile
  6. 2 2
      dev/containers/Dockerfile
  7. 4 2
      server/graph/resolvers/user.js
  8. 1 0
      server/graph/schemas/user.graphql
  9. 8 4
      server/models/users.js
  10. 7 3
      server/modules/authentication/auth0/authentication.js
  11. 5 4
      server/modules/authentication/azure/authentication.js
  12. 14 9
      server/modules/authentication/cas/authentication.js
  13. 6 5
      server/modules/authentication/discord/authentication.js
  14. 5 4
      server/modules/authentication/dropbox/authentication.js
  15. 5 4
      server/modules/authentication/facebook/authentication.js
  16. 9 7
      server/modules/authentication/firebase/authentication.js
  17. 5 4
      server/modules/authentication/github/authentication.js
  18. 5 4
      server/modules/authentication/gitlab/authentication.js
  19. 5 4
      server/modules/authentication/google/authentication.js
  20. 8 7
      server/modules/authentication/keycloak/authentication.js
  21. 3 3
      server/modules/authentication/ldap/authentication.js
  22. 5 5
      server/modules/authentication/microsoft/authentication.js
  23. 12 7
      server/modules/authentication/oauth2/authentication.js
  24. 6 5
      server/modules/authentication/oidc/authentication.js
  25. 5 4
      server/modules/authentication/okta/authentication.js
  26. 5 4
      server/modules/authentication/saml/authentication.js
  27. 5 4
      server/modules/authentication/slack/authentication.js
  28. 5 4
      server/modules/authentication/twitch/authentication.js

+ 2 - 1
client/components/admin/admin-users-edit.vue

@@ -125,7 +125,7 @@
                 v-icon mdi-domain
               v-list-item-content
                 v-list-item-title {{$t('admin:users.authProvider')}}
-                v-list-item-subtitle {{ user.providerKey }}
+                v-list-item-subtitle {{ user.providerName }} #[em.caption ({{ user.providerKey }})]
               //- v-list-item-action
               //-   v-img(src='https://static.requarks.io/logo/wikijs.svg', alt='', contain, max-height='32', position='center right')
             template(v-if='user.providerKey === `local`')
@@ -953,6 +953,7 @@ export default {
               name
               email
               providerKey
+              providerName
               providerId
               location
               jobTitle

+ 4 - 1
client/components/admin/admin-users.vue

@@ -57,7 +57,7 @@
                 td {{ props.item.id }}
                 td: strong {{ props.item.name }}
                 td {{ props.item.email }}
-                td {{ props.item.providerKey }}
+                td {{ getStrategyName(props.item.providerKey) }}
                 td {{ props.item.createdAt | moment('from') }}
                 td
                   span(v-if='props.item.lastLoginAt') {{ props.item.lastLoginAt | moment('from') }}
@@ -131,6 +131,9 @@ export default {
           icon: 'cached'
         })
       }
+    },
+    getStrategyName(key) {
+      return (_.find(this.strategies, ['key', key]) || {}).displayName || key
     }
   },
   apollo: {

+ 1 - 1
client/components/profile/profile.vue

@@ -161,7 +161,7 @@
                 autocomplete='off'
                 hide-details
                 )
-          v-card-chin
+          v-card-chin(v-if='user.providerKey === `local`')
             v-spacer
             v-btn.px-4(color='purple darken-4', dark, depressed, @click='changePassword', :loading='changePassLoading')
               v-icon(left) mdi-progress-check

+ 2 - 2
dev/build-arm/Dockerfile

@@ -1,7 +1,7 @@
 # =========================
 # --- BUILD NPM MODULES ---
 # =========================
-FROM node:12-alpine AS build
+FROM node:14-alpine AS build
 
 RUN apk add yarn g++ make python --no-cache
 
@@ -14,7 +14,7 @@ RUN yarn --production --frozen-lockfile --non-interactive --network-timeout 1000
 # ===============
 # --- Release ---
 # ===============
-FROM node:12-alpine
+FROM node:14-alpine
 LABEL maintainer="requarks.io"
 
 RUN apk add bash curl git openssh gnupg sqlite --no-cache && \

+ 3 - 3
dev/build/Dockerfile

@@ -1,7 +1,7 @@
 # ====================
 # --- Build Assets ---
 # ====================
-FROM node:12-alpine AS assets
+FROM node:14-alpine AS assets
 
 RUN apk add yarn g++ make python --no-cache
 
@@ -23,10 +23,10 @@ RUN yarn --production --frozen-lockfile --non-interactive
 # ===============
 # --- Release ---
 # ===============
-FROM node:12-alpine
+FROM node:14-alpine
 LABEL maintainer="requarks.io"
 
-RUN apk add bash curl git openssh gnupg sqlite --no-cache && \
+RUN apk add bash curl git openssh gnupg sqlite pandoc --no-cache && \
     mkdir -p /wiki && \
     mkdir -p /logs && \
     mkdir -p /wiki/data/content && \

+ 2 - 2
dev/containers/Dockerfile

@@ -1,11 +1,11 @@
 # -- DEV DOCKERFILE --
 # -- DO NOT USE IN PRODUCTION! --
 
-FROM node:12
+FROM node:14
 LABEL maintainer "requarks.io"
 
 RUN apt-get update && \
-    apt-get install -y bash curl git python make g++ nano openssh-server gnupg && \
+    apt-get install -y bash curl git python make g++ nano openssh-server gnupg pandoc && \
     mkdir -p /wiki
 
 WORKDIR /wiki

+ 4 - 2
server/graph/resolvers/user.js

@@ -23,9 +23,11 @@ module.exports = {
         .select('id', 'email', 'name', 'providerKey', 'createdAt')
     },
     async single(obj, args, context, info) {
+      console.info(WIKI.auth.strategies)
       let usr = await WIKI.models.users.query().findById(args.id)
       usr.password = ''
       usr.tfaSecret = ''
+      usr.providerName = _.get(WIKI.auth.strategies, usr.providerKey).displayName
       return usr
     },
     async profile (obj, args, context, info) {
@@ -37,9 +39,9 @@ module.exports = {
         throw new WIKI.Error.AuthAccountBanned()
       }
 
-      const providerInfo = _.find(WIKI.data.authentication, ['key', usr.providerKey])
+      const providerInfo = _.get(WIKI.auth.strategies, usr.providerKey, {})
 
-      usr.providerName = _.get(providerInfo, 'title', 'Unknown')
+      usr.providerName = providerInfo.displayName || 'Unknown'
       usr.lastLoginAt = usr.lastLoginAt || usr.updatedAt
       usr.password = ''
       usr.providerId = ''

+ 1 - 0
server/graph/schemas/user.graphql

@@ -128,6 +128,7 @@ type User {
   name: String!
   email: String!
   providerKey: String!
+  providerName: String
   providerId: String
   isSystem: Boolean!
   isActive: Boolean!

+ 8 - 4
server/models/users.js

@@ -163,7 +163,7 @@ module.exports = class User extends Model {
 
   static async processProfile({ profile, providerKey }) {
     const provider = _.get(WIKI.auth.strategies, providerKey, {})
-    provider.info = _.find(WIKI.data.authentication, ['key', providerKey])
+    provider.info = _.find(WIKI.data.authentication, ['key', provider.stategyKey])
 
     // Find existing user
     let user = await WIKI.models.users.query().findOne({
@@ -273,7 +273,8 @@ module.exports = class User extends Model {
 
   static async login (opts, context) {
     if (_.has(WIKI.auth.strategies, opts.strategy)) {
-      const strInfo = _.find(WIKI.data.authentication, ['key', opts.strategy])
+      const selStrategy = _.get(WIKI.auth.strategies, opts.strategy)
+      const strInfo = _.find(WIKI.data.authentication, ['key', selStrategy.strategyKey])
 
       // Inject form user/pass
       if (strInfo.useForm) {
@@ -283,7 +284,7 @@ module.exports = class User extends Model {
 
       // Authenticate
       return new Promise((resolve, reject) => {
-        WIKI.auth.passport.authenticate(opts.strategy, {
+        WIKI.auth.passport.authenticate(selStrategy.strategyKey, {
           session: !strInfo.useForm,
           scope: strInfo.scopes ? strInfo.scopes : null
         }, async (err, user, info) => {
@@ -291,7 +292,10 @@ module.exports = class User extends Model {
           if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) }
 
           try {
-            const resp = await WIKI.models.users.afterLoginChecks(user, context)
+            const resp = await WIKI.models.users.afterLoginChecks(user, context, {
+              skipTFA: !strInfo.useForm,
+              skipChangePwd: !strInfo.useForm
+            })
             resolve(resp)
           } catch (err) {
             reject(err)

+ 7 - 3
server/modules/authentication/auth0/authentication.js

@@ -13,10 +13,14 @@ module.exports = {
         domain: conf.domain,
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
-      }, async (accessToken, refreshToken, extraParams, profile, cb) => {
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, extraParams, profile, cb) => {
         try {
-          const user = await WIKI.models.users.processProfile({ profile, providerKey: 'auth0' })
+          const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
+            profile
+          })
           cb(null, user)
         } catch (err) {
           cb(err, null)

+ 5 - 4
server/modules/authentication/azure/authentication.js

@@ -18,18 +18,19 @@ module.exports = {
         responseType: 'id_token',
         responseMode: 'form_post',
         scope: ['profile', 'email', 'openid'],
-        allowHttpForRedirectUrl: WIKI.IS_DEBUG
-      }, async (iss, sub, profile, cb) => {
+        allowHttpForRedirectUrl: WIKI.IS_DEBUG,
+        passReqToCallback: true
+      }, async (req, iss, sub, profile, cb) => {
         const usrEmail = _.get(profile, '_json.email', null) || _.get(profile, '_json.preferred_username')
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               id: profile.oid,
               displayName: profile.displayName,
               email: usrEmail,
               picture: ''
-            },
-            providerKey: 'azure'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 14 - 9
server/modules/authentication/cas/authentication.js

@@ -11,14 +11,19 @@ module.exports = {
     passport.use('cas',
       new CASStrategy({
         ssoBaseURL: conf.ssoBaseURL,
-        serverBaseURL: conf.serverBaseURL
-      }, (profile, cb) => {
-        WIKI.models.users.processProfile(profile).then((user) => {
-          return cb(null, user) || true
-        }).catch((err) => {
-          return cb(err, null) || true
-        })
-      }
-      ))
+        serverBaseURL: conf.serverBaseURL,
+        passReqToCallback: true
+      }, async (req, profile, cb) => {
+        try {
+          const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
+            profile
+          })
+          cb(null, user)
+        } catch (err) {
+          cb(err, null)
+        }
+      })
+    )
   }
 }

+ 6 - 5
server/modules/authentication/discord/authentication.js

@@ -15,19 +15,20 @@ module.exports = {
         clientSecret: conf.clientSecret,
         authorizationURL: 'https://discord.com/api/oauth2/authorize?prompt=none',
         callbackURL: conf.callbackURL,
-        scope: 'identify email guilds'
-      }, async (accessToken, refreshToken, profile, cb) => {
+        scope: 'identify email guilds',
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
-		      if (conf.guildId && !_.some(profile.guilds, { id: conf.guildId })) {
+          if (conf.guildId && !_.some(profile.guilds, { id: conf.guildId })) {
             throw new WIKI.Error.AuthLoginFailed()
           }
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               displayName: profile.username,
               picture: `https://cdn.discordapp.com/avatars/${profile.id}/${profile.avatar}.png`
-            },
-            providerKey: 'discord'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/dropbox/authentication.js

@@ -14,15 +14,16 @@ module.exports = {
         apiVersion: '2',
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
-      }, async (accessToken, refreshToken, profile, cb) => {
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, '_json.profile_photo_url', '')
-            },
-            providerKey: 'dropbox'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/facebook/authentication.js

@@ -15,15 +15,16 @@ module.exports = {
         clientSecret: conf.clientSecret,
         callbackURL: conf.callbackURL,
         profileFields: ['id', 'displayName', 'email', 'photos'],
-        authType: 'reauthenticate'
-      }, async (accessToken, refreshToken, profile, cb) => {
+        authType: 'reauthenticate',
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'photos[0].value', '')
-            },
-            providerKey: 'facebook'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 9 - 7
server/modules/authentication/firebase/authentication.js

@@ -1,28 +1,30 @@
 /* global WIKI */
 
 // ------------------------------------
-// GitHub Account
+// Firebase Account
 // ------------------------------------
 
-const GitHubStrategy = require('passport-github2').Strategy
+// INCOMPLETE / TODO
+
+const FirebaseStrategy = require('passport-github2').Strategy
 const _ = require('lodash')
 
 module.exports = {
   init (passport, conf) {
-    passport.use('github',
-      new GitHubStrategy({
+    passport.use('firebase',
+      new FirebaseStrategy({
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
         callbackURL: conf.callbackURL,
         scope: ['user:email']
-      }, async (accessToken, refreshToken, profile, cb) => {
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'photos[0].value', '')
-            },
-            providerKey: 'github'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/github/authentication.js

@@ -13,7 +13,8 @@ module.exports = {
       clientID: conf.clientId,
       clientSecret: conf.clientSecret,
       callbackURL: conf.callbackURL,
-      scope: ['user:email']
+      scope: ['user:email'],
+      passReqToCallback: true
     }
 
     if (conf.useEnterprise) {
@@ -24,14 +25,14 @@ module.exports = {
     }
 
     passport.use('github',
-      new GitHubStrategy(githubConfig, async (accessToken, refreshToken, profile, cb) => {
+      new GitHubStrategy(githubConfig, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'photos[0].value', '')
-            },
-            providerKey: 'github'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/gitlab/authentication.js

@@ -15,15 +15,16 @@ module.exports = {
         clientSecret: conf.clientSecret,
         callbackURL: conf.callbackURL,
         baseURL: conf.baseUrl,
-        scope: ['read_user']
-      }, async (accessToken, refreshToken, profile, cb) => {
+        scope: ['read_user'],
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'avatarUrl', '')
-            },
-            providerKey: 'gitlab'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/google/authentication.js

@@ -13,15 +13,16 @@ module.exports = {
       new GoogleStrategy({
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
-      }, async (accessToken, refreshToken, profile, cb) => {
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'photos[0].value', '')
-            },
-            providerKey: 'google'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 8 - 7
server/modules/authentication/keycloak/authentication.js

@@ -12,28 +12,29 @@ module.exports = {
   init (passport, conf) {
     passport.use('keycloak',
       new KeycloakStrategy({
-	      authorizationURL: conf.authorizationURL,
-	      userInfoURL: conf.userInfoURL,
+        authorizationURL: conf.authorizationURL,
+        userInfoURL: conf.userInfoURL,
         tokenURL: conf.tokenURL,
-	      host: conf.host,
+        host: conf.host,
         realm: conf.realm,
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
-      }, async (accessToken, refreshToken, profile, cb) => {
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         let displayName = profile.username
         if (_.isString(profile.fullName) && profile.fullName.length > 0) {
           displayName = profile.fullName
         }
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               id: profile.keycloakId,
               email: profile.email,
               name: displayName,
               picture: ''
-            },
-            providerKey: 'keycloak'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 3 - 3
server/modules/authentication/ldap/authentication.js

@@ -28,7 +28,7 @@ module.exports = {
         usernameField: 'email',
         passwordField: 'password',
         passReqToCallback: false
-      }, async (profile, cb) => {
+      }, async (req, profile, cb) => {
         try {
           const userId = _.get(profile, conf.mappingUID, null)
           if (!userId) {
@@ -36,13 +36,13 @@ module.exports = {
           }
 
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               id: userId,
               email: String(_.get(profile, conf.mappingEmail, '')).split(',')[0],
               displayName: _.get(profile, conf.mappingDisplayName, '???'),
               picture: _.get(profile, conf.mappingPicture, '')
-            },
-            providerKey: 'ldap'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 5
server/modules/authentication/microsoft/authentication.js

@@ -14,16 +14,16 @@ module.exports = {
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
         callbackURL: conf.callbackURL,
-        scope: ['User.Read', 'email', 'openid', 'profile']
-      }, async (accessToken, refreshToken, profile, cb) => {
-        console.info(profile)
+        scope: ['User.Read', 'email', 'openid', 'profile'],
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'photos[0].value', '')
-            },
-            providerKey: 'microsoft'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 12 - 7
server/modules/authentication/oauth2/authentication.js

@@ -14,13 +14,18 @@ module.exports = {
         tokenURL: conf.tokenURL,
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
-      }, (accessToken, refreshToken, profile, cb) => {
-        WIKI.models.users.processProfile(profile).then((user) => {
-          return cb(null, user) || true
-        }).catch((err) => {
-          return cb(err, null) || true
-        })
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
+        try {
+          const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
+            profile
+          })
+          cb(null, user)
+        } catch (err) {
+          cb(err, null)
+        }
       })
     )
   }

+ 6 - 5
server/modules/authentication/oidc/authentication.js

@@ -18,18 +18,19 @@ module.exports = {
         clientSecret: conf.clientSecret,
         issuer: conf.issuer,
         userInfoURL: conf.userInfoURL,
-        callbackURL: conf.callbackURL
-      }, async (iss, sub, profile, cb) => {
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, iss, sub, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               email: _.get(profile, '_json.' + conf.emailClaim)
-            },
-            providerKey: 'oidc'
+            }
           })
           cb(null, user)
-        } catch(err) {
+        } catch (err) {
           cb(err, null)
         }
       })

+ 5 - 4
server/modules/authentication/okta/authentication.js

@@ -16,15 +16,16 @@ module.exports = {
         clientSecret: conf.clientSecret,
         idp: conf.idp,
         callbackURL: conf.callbackURL,
-        response_type: 'code'
-      }, async (accessToken, refreshToken, profile, cb) => {
+        response_type: 'code',
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, '_json.profile', '')
-            },
-            providerKey: 'okta'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/saml/authentication.js

@@ -22,7 +22,8 @@ module.exports = {
       forceAuthn: conf.forceAuthn,
       providerName: conf.providerName,
       skipRequestCompression: conf.skipRequestCompression,
-      authnRequestBinding: conf.authnRequestBinding
+      authnRequestBinding: conf.authnRequestBinding,
+      passReqToCallback: true
     }
     if (!_.isEmpty(conf.audience)) {
       samlConfig.audience = conf.audience
@@ -37,7 +38,7 @@ module.exports = {
       samlConfig.decryptionPvk = conf.decryptionPvk
     }
     passport.use('saml',
-      new SAMLStrategy(samlConfig, async (profile, cb) => {
+      new SAMLStrategy(samlConfig, async (req, profile, cb) => {
         try {
           const userId = _.get(profile, [conf.mappingUID], null) || _.get(profile, 'nameID', null)
           if (!userId) {
@@ -45,13 +46,13 @@ module.exports = {
           }
 
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               id: userId,
               email: _.get(profile, conf.mappingEmail, ''),
               displayName: _.get(profile, conf.mappingDisplayName, '???'),
               picture: _.get(profile, conf.mappingPicture, '')
-            },
-            providerKey: 'saml'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/slack/authentication.js

@@ -14,15 +14,16 @@ module.exports = {
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
         callbackURL: conf.callbackURL,
-        team: conf.team
-      }, async (accessToken, scopes, team, extra, { user: userProfile }, cb) => {
+        team: conf.team,
+        passReqToCallback: true
+      }, async (req, accessToken, scopes, team, extra, { user: userProfile }, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...userProfile,
               picture: _.get(userProfile, 'image_48', '')
-            },
-            providerKey: 'slack'
+            }
           })
           cb(null, user)
         } catch (err) {

+ 5 - 4
server/modules/authentication/twitch/authentication.js

@@ -13,15 +13,16 @@ module.exports = {
       new TwitchStrategy({
         clientID: conf.clientId,
         clientSecret: conf.clientSecret,
-        callbackURL: conf.callbackURL
-      }, async (accessToken, refreshToken, profile, cb) => {
+        callbackURL: conf.callbackURL,
+        passReqToCallback: true
+      }, async (req, accessToken, refreshToken, profile, cb) => {
         try {
           const user = await WIKI.models.users.processProfile({
+            providerKey: req.params.strategy,
             profile: {
               ...profile,
               picture: _.get(profile, 'avatar', '')
-            },
-            providerKey: 'twitch'
+            }
           })
           cb(null, user)
         } catch (err) {