coralproject / talk

A better commenting experience from Vox Media
https://coralproject.net
Other
1.89k stars 355 forks source link

Custom SSO with Okta authentication provider. #2285

Closed brvaland closed 5 years ago

brvaland commented 5 years ago

Hi

I would like to integration coral talk with Okta for SSO and it is not working. I am newbie to talk and plugins. I am not sure what i need to specify for TALK_JWT_SECRET as OKTA using JSON Web Key Set - https://developer.okta.com/code/dotnet/jwt-validation/

I have done the following setups

module.exports = {

// When the JWT is passed to Talk, first it will be validated // Next, Talk will attempt to locate a user in its DB using the token's sub claim, // if the user is not found, the tokenUserNotFound hook will be called to create the user tokenUserNotFound: async ({ jwt }) => { debug('The jwt is ' + JSON.stringify(jwt));

// Since the JWT has already been validated we can pass it's claims directly to upsertExternalUser
const user = await Users.upsertExternalUser(
  null,
  jwt.sub,
  jwt.iss,
  jwt.username
);

// Persisting email address in Talk is required only if sending notifications from Talk.
// If email was included on the JWT we can add it to a "local" profile
// and push that into the user's Profiles array. 
// To avoid duplication of Profiles, you may want add a check if user.wasUpserted
// upsertExternalUser above will also create a profile as: { provider:jwt.iss, id:jwt.sub }
const email = jwt.email.toLowerCase();
user.profiles.push({
  provider: 'local',
  id: email,
});

// Then handle any additional User fields that you'd like to persist in Talk 
// In this example a "memberSince" claim containing a unix timestamp on the jwt 
// is used to overwrite created_at date
// You can use the User.metadata property to store additional custom user details
user.created_at = jwt.memberSince
  ? new Date(jwt.memberSince * 1000)
  : Date.now();

// Finally, save and return the User that was created  
await user.save();
debug('The user created is ' + JSON.stringify(user));
return user;

},

// At this point we've handled creating new users, // now let's handle updating a user that was created by our tokenUserNotFound hook. // This implementation assumes that the external auth service calls the TALK_ROOT_URL/plugin/update-user endpoint // with a valid jwt token anytime a user is update needs to be passed to Talk // First we add the `/plugin/update-user`` route and secure it with ADMIN level permissions router: router => { router.post( '/plugin/update-user', authz.needed('ADMIN'), async (req, res, next) => { const { body: { token }, context: { connectors: { models: { User }, }, }, } = req;

    // Since the token is being passed directly to the route in this case,
    // we need to parse it and should validate it's claims
    try {
      const { sub, username, email, iss } = JSON.parse(
        Buffer.from(token.split('.')[1], 'base64').toString()
      );
      // Finally we call findOneAndUpdate to locate, update, and return the User from Talk's DB
      // Be sure to update any and all fields that were set by the tokenUserNotFoundHook
      let user = await User.findOneAndUpdate(
        { $or: [{ sub }, { 'profiles.id': sub }] },
        {
          $set: {
            username: username,
            lowercaseUsername: username.toLowerCase(),
            profiles: [
              {
                provider: 'local',
                id: email,
              },
              {
                provider: iss,
                id: sub,
              },
            ],
          },
        },
        {
          new: true,
        }
      );
      return res.json({ user });
    } catch (e) {
      return next(e);
    }
  }
);

},

// This last step is completely OPTIONAL, // and only applies if you need to override a standard Talk data point with your own custom value. // This example assumes that I've stored a custom displayName value in the User.metadata property // Here we will reference the value in User.metadata.displayName everywhere that User.username is shown in Talk resolvers: { User: { username: user => get(user, 'metadata.displayName', get(user, 'username')), }, }, };



Any help will be appreciated.

Thanks
Bhavesh
brvaland commented 5 years ago

Further update on my issue, i have managed to get public signing key from okta - https://developer.okta.com/docs/api/resources/oidc/#keys

I have converted JWK to PEM using this tool - https://8gwifi.org/jwkconvertfunctions.jsp

Replaced TALK_JWT_SECRET with TALK_JWT_SECRETS as below

TALK_JWT_SECRETS=[{"kid":"-0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY","public":"-----BEGIN PUBLIC KEY-----\\n*******************\\n-----END PUBLIC KEY-----\\n"}]

I have verified token (jwt.io) as below.


{
  "kid": "-0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY",
  "alg": "RS256"
}

{
  "ver": 1,
  "jti": "AT.mExZ7QrNCgJbSLGaZnAKLxWNhHn4Qsq7nY9d9kHFRDQ",
  "iss": "https://dev-***.oktapreview.com/oauth2/default",
  "aud": "api://default",
  "iat": 1556192231,
  "exp": 1556195831,
  "cid": "0oakhu3pfpTyVhl160h7",
  "uid": "00ufwg9tbbeCc4bnh0h7",
  "scp": [
    "openid"
  ],
  "sub": "******"
}```
wyattjoh commented 5 years ago

Great questions. What might be happening is it seems you don't have a private key associated in the TALK_JWT_SECRETS variable, which should have a private key in the first element of the JSON array as mentioned in https://github.com/coralproject/talk/issues/2273.

Are you also sure that you've included your plugin in the server portion of the plugins.json file? You can add a console.log to the router hook (before you call router.post) to see if it's called at all, or use DEBUG=talk:plugins to see if log out.

Last thing I'll mention is that currently, v4 of Talk does not support JWKs directly, which means if Okta rotates the public keys, you will need to update Talk directly. The next version of Talk should support this much more easily.

brvaland commented 5 years ago

@wyattjoh - i add try to add two keys as below but got an error

TALK_JWT_SECRETS=[{"kid":"oCQeSqSF","private":"-----BEGIN RSA PRIVATE KEY-----\\nMIIEpAIBAAKCAQEAyqwTfd+39oP+pEy1CnXdVmu606LHZzgcfcagRl7NCjHa5QjX\\nD6fCkK/44GNvKKp9YuGiMPzugZIDHQpR971K8mn+YDd7YdwPWaXOeY9x+vJa6lSy\\noeGcWoM1GvktqjWuXxD2EjS5MpN8wtPjd5jMOvHYszukTvH+9cNu++wbrwNq05Ho\\nmNURwoBP9GIg2B3dMWYymZalW5gWYdm7ETyJaWINf+3bVmAy5MbFBX8424SBRwXj\\nxpjBRTFpTRj+ENqAJ9ICvMivNQtFOTTlkSlo1M65WJAJOf5lFEnDmaSrV7YeqQof\\nydPJOhdRNVKf62OeKrNTgmr/0hYuWROLSUxX+wIDAQABAoIBAQCmuaIbRaRXhkQ/\\nst6n6UgY5Oy/V0SElDNUAMcuvKQeQ98X1QreVRqI3kp1hTcXlBEr/APqGti1/IDV\\nLf06OR1jiHB7hIjaeyahj/XoKGoSj7bc2KpO44M1LoTMWLoJMLnueMyFM5w6j/vt\\nZlPUuf0gbH3hDCphy0/7qzcsxRINCOIzMAxgx+LFvrMBqvUElC9KB5ARXhOFHVzC\\nIFNYl6hld8dy0/NgUEggnAxASIPj4fykPNiShP9Z4linhjv2k2BZmQ18Bu4+gac6\\nbbbbmyN5CHH8ta4xeTyGxP/XjVLlQS/ELytDG1FybS2d+sIPGjR7HFpGOnHXkCLU\\nNM61iEQpAoGBAPHXKGoQXzm1Ek+N8+AxiuFTtcZEkT2NHL0Rv3t1KiKqwevynu4U\\nLZ5i2QWW21z6s0T11TXwnIYI7NTkjvh5MOcSF7Mv06hW3/iOW10DAgnscujxybHK\\nIegNCJqk9zBejLMlxWTXlX0tWFgWCNJk8f/Qonpg7GGkDrirJn/qpBndAoGBANaJ\\n13u6QWU1qlJRT1xqroZv74AV88ockdZ+DpuhDYxtYTSuLL396Z+tH71QFdVtkKGa\\noF8hKykMtZ4LH+SbNAORUl0DDWnMalcjHzvTE6LT7AXJcXNFc4yIJHGNIipKZtEK\\nhZ6hW0Ot+YGfm2Yk1HQbz3mpY9/m+W0j4ejrJxe3AoGBAKoUEL4W6YFiEJCWWm7P\\nKMay4mGfky1gcledhbbDfXCH+n1/UbpJwpNjHRFLONa5ER5sbRfUMaAp4rUOUGX6\\nhSPcm4JPHmGDR1w8cZCGLwbfnSip8pjweMwDboujfJwtwnGzHJGA9Abmvvyj8mxU\\nxcSM69d5FoTMpfXFl/vZ/rKZAoGAPoFOjLfJUcl+5BjYfF6Alp6KMtEyhBIq00lK\\nzEDyB5XemlCcrIYLyP/RnYB1vAb9+ndofg7V2lHfoDoxgpNNZjSywHKhN8/cs6KB\\n+RYYRHpl65GzQhhb//eyVnr+F0AyEHl2UK9GPcO0S/XKesoENAfePN4DQTq0NP4d\\nVZUdgKUCgYAwrUDNg0PhuShozkqAm17VsW8b0WBxk6Co35YrNnOz5MJ6tk2gnFed\\nEjkhmaOmCqTrUX00/1BWaqvEmLFeejSLed7qaHoL0Ei6swp1kv4bhB3VPcruiOFP\\n7+MNVgz3T9RJ4ZcnIy21IfGSVSCJS7dFO6mhbdnTHUyNFfRsJHMqsg==\\n-----END RSA PRIVATE KEY-----\\n","public":"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqwTfd+39oP+pEy1CnXd\\nVmu606LHZzgcfcagRl7NCjHa5QjXD6fCkK/44GNvKKp9YuGiMPzugZIDHQpR971K\\n8mn+YDd7YdwPWaXOeY9x+vJa6lSyoeGcWoM1GvktqjWuXxD2EjS5MpN8wtPjd5jM\\nOvHYszukTvH+9cNu++wbrwNq05HomNURwoBP9GIg2B3dMWYymZalW5gWYdm7ETyJ\\naWINf+3bVmAy5MbFBX8424SBRwXjxpjBRTFpTRj+ENqAJ9ICvMivNQtFOTTlkSlo\\n1M65WJAJOf5lFEnDmaSrV7YeqQofydPJOhdRNVKf62OeKrNTgmr/0hYuWROLSUxX\\n+wIDAQAB\\n-----END PUBLIC KEY-----\\n"},{"kid":"-0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY","public":"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAocJ2TOVAjK0dFvapf6Yd\\nk1KJbv6xY/mFYlJhXnnCGxZC+raItUkvqJ875J7Vcc72FAnaTBgYLZb39QWU6sn1\\nOihbSAhgjCm7J9hNwp20CZ/oh47IMziIKw3Rly8ejFTH1cTCtHQOBAaHxhtcmKRe\\n3PuPvB76bV5VW+1NiZSzpE5EV39HHt2OYGrAzczmZ6Z2uqCc4JhAQkbp1yBJNMAC\\nvYEN5MSnqgG8RHIqlC3rHjY9PAQsZE+u54zVxDH4tDoGrA8QKMJdMIVjxBDocLVa\\nSs56yN6k3b+odzHK9XsF\\n13CRPCNh/7bL2Vw4q+iD7rL6GtG2Ey6k2axtTRREeTy\\nzwIDAQAB\\n-----END PUBLIC KEY-----\\n"}]

Once i add above to .env file i am getting the folllowing error.

    ^

Error: Secret cannot have a zero length
    at new SharedSecret (C:\talk\services\jwt.js:120:11)
    at module.exports.jwt.jwt.MultiSecret.JWT_SECRETS.map.secret (C:\talk\secrets.js:34:16)
    at Array.map (<anonymous>)
    at Object.<anonymous> (C:\talk\secrets.js:21:17)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (C:\talk\services\users.js:26:29)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)

Thanks for pointing out the plugins.json file but is there any issue with TALK_JWT_SECRETS

maveonair commented 5 years ago

@brvaland Could you please post your whole .env file?

brvaland commented 5 years ago

@wyattjoh, @maveonair I have managed to get above error resolved typo for 'TALK_JWT_ALG' but still tokenUserNotFound is not called.

I can see my plugin get executed as i get output from the console.log that i added router.post.

Here is updated .env file content and i now have private key in first element.

NODE_ENV=development
TALK_MONGO_URL=mongodb://127.0.0.1:27017/talk
TALK_REDIS_URL=redis://127.0.0.1:6379
TALK_ROOT_URL=http://127.0.0.1:3000
TALK_PORT=3000
TALK_JWT_ISSUER=https://dev-847522.oktapreview.com/oauth2/default
TALK_JWT_AUDIENCE=api://default
TALK_JWT_SECRETS=[{"kid":"KHi6VPf9","private":"-----BEGIN RSA PRIVATE KEY-----\\nMIIEpQIBAAKCAQEA0irzhKnbJtm2dEaLqlLH6HNGXGe8ID9QUQGXZCPXVmxrqlHw\\n+FMhK1gJTuww8GpsEX2lTXbWr4cEacFYB4haxOhP6MvpyanxGJIx1octJyeaHgzF\\nQZ5wFWXm6uGU4OQAFoZAbWKsutr1xRTr1FOjHQG7U+5r8/nxJkoAbF31qwZuwc0/\\nAXzQr4Q6R38ILIdZzH0jOxkEA1CoOyJVix91waFpTggD7Axs4ktKmLBPtnkiu86F\\npEP2Ju6qFbGef/p8Xxa3f0kz3R4WQaIUpRAxe49BGc/1De8uYcfiDHaJeAXWvrt2\\nNKDlS2vwcMLQfIdFAgTR1QhpCAY4LMILXrEEBwIDAQABAoIBAQDRz9NAM5n3FQ3S\\n0sKHjRDJfJtXkK/8uXhjBmWusSE+xApQBHG+Vq8caE0SnzTULkoow/iMdwEoRnAf\\na8eH7ZZAUXPFAh0pGCD62KgsdNKc7iorqbAbLCLVGeAHyKAqSzPTSL909Ddga0tE\\nLvioBb8nLB1pUvIupO0bvnDhvoOM8ZWUtmqPWHwNixWGyIGJT2hhbKId23lWsENu\\nUayQdrXhvW+aagvNkTKh6FVmC564/d/mzX6HYw1gu5Fbr6kca0iNuMjOaPuAWIJ4\\nUGHy5M4PepaMtzouxLSefj+JoZjeKBh9PRzG/uUVmtwJR8oXXrTNpBz4iKx12t/O\\n4CPsSZxBAoGBAN9DTHeq9KiPTG0AruK14/XbKtqqGREFj+66oLS2BoHEGs6KchXX\\nmo1cBNa4Yj64kkq79/umJj0w3+FfL1wi0yMcFVL+PkeT2IDMuDTmjHvpHyvxJG75\\nSvC3InhDsU2K85IG7m9ED5nNN3ir+ooOu5778b8zVAybL3Wtzh5Ygto3AoGBAPD8\\nGL9dWAoNRIWsLatUV7W7ojNdZi+5r+AkhwBB9nTSbsUt9f0jTUGXTs4ouCnP9ID5\\nxIjsxrDMxBiHjRA1heztc0rq2pmca0zY4/ry7XoQlaNEbaybMyuxuZZsEkSHA3O0\\nqBMLqUO2XKdlG1a/pgWu1Ks0ndfBTbfyq7Mw5vyxAoGATE5VEUVlr0KizVKBc0zV\\nZ88Le4bNYGr1QZOZn4ni+XEL9HGPAnYZBZ1grf6A3Yz5uv85h1HHGfzdV8rPhf8F\\nCKfthdsNcCtQwNy3TKVLeII5vCwD1sXvXgxJhK8mJymJi+xAi9jIODnSbrTgwVS9\\nvV3AxyeE33Yep2rK2sZHmssCgYEAj92glJYQWifjkX3h4de/aSI0Sj/nInTTd5e2\\n9MNsc/+w24x9v3rUw2SmSlNq5qNcj6cM2sWoNKJ6Kz65S0T4yCJV4xLkIDKOqFkP\\neaCPf4DpJIhUhWg+G0bFyfSIz1pfCDOA56XdjiwPkmu874QIhHoEQpVt6gFf+YIp\\nWRfHvnECgYEAg4FRs/7IBoyYVmoU0qqFqVpzWb3VYkKW0cd8ZJrvSqVSdI5Qfi4Y\\n3f1DKdE85tRxALbDQ+TDiglBdp32/2+eYx/HheVr8tT27NBcrvzJsmaxGm3EfEIB\\nMhDub1imG/l/1EU60TOiZNGY6XawSlGtKg5uS1xb+A/6h/d6R9al2CE=\\n-----END RSA PRIVATE KEY-----\\n","public":"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0irzhKnbJtm2dEaLqlLH\\n6HNGXGe8ID9QUQGXZCPXVmxrqlHw+FMhK1gJTuww8GpsEX2lTXbWr4cEacFYB4ha\\nxOhP6MvpyanxGJIx1octJyeaHgzFQZ5wFWXm6uGU4OQAFoZAbWKsutr1xRTr1FOj\\nHQG7U+5r8/nxJkoAbF31qwZuwc0/AXzQr4Q6R38ILIdZzH0jOxkEA1CoOyJVix91\\nwaFpTggD7Axs4ktKmLBPtnkiu86FpEP2Ju6qFbGef/p8Xxa3f0kz3R4WQaIUpRAx\\ne49BGc/1De8uYcfiDHaJeAXWvrt2NKDlS2vwcMLQfIdFAgTR1QhpCAY4LMILXrEE\\nBwIDAQAB\\n-----END PUBLIC KEY-----\\n"}, {"kid": "-0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY", "public": "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAocJ2TOVAjK0dFvapf6Yd\\nk1KJbv6xY/mFYlJhXnnCGxZC+raItUkvqJ875J7Vcc72FAnaTBgYLZb39QWU6sn1\\nOihbSAhgjCm7J9hNwp20CZ/oh47IMziIKw3Rly8ejFTH1cTCtHQOBAaHxhtcmKRe\\n3PuPvB76bV5VW+1NiZSzpE5EV39HHt2OYGrAzczmZ6Z2uqCc4JhAQkbp1yBJNMAC\\nvYEN5MSnqgG8RHIqlC3rHjY9PAQsZE+u54zVxDH4tDoGrA8QKMJdMIVjxBDocLVa\\nSs56yN6k3b+odzHK9XsF+13CRPCNh/7bL2Vw4q+iD7rL6GtG2Ey6k2axtTRREeTy\\nzwIDAQAB\\n-----END PUBLIC KEY-----"}]
TALK_JWT_ALG=RSA256
DEBUG=talk:plugins

Here is log from console and added console.log in services/jwt.js - veriy method.

yarn run v1.13.0
$ cross-env NODE_ENV=production ./bin/cli-serve -j -w
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"workerID":1,"msg":"started worker","time":"2019-04-26T12:50:07.058Z","src":{"file":"C:\\talk\\bin\\cli-serve","line":30,"func":"start"},"v":0}
  talk:plugins Now using C:\talk\plugins.default.json for plugins +0ms
  talk:plugins loading internal plugin 'talk-plugin-featured-comments' from 'C:\talk\plugins\talk-plugin-featured-comments\index.js' +2s
  talk:plugins loading internal plugin 'talk-plugin-local-auth' from 'C:\talk\plugins\talk-plugin-local-auth\index.js' +9ms
  talk:plugins loading internal plugin 'talk-plugin-profile-data' from 'C:\talk\plugins\talk-plugin-profile-data\index.js' +210ms
  talk:plugins loading internal plugin 'talk-plugin-respect' from 'C:\talk\plugins\talk-plugin-respect\index.js' +20ms
  talk:plugins loading internal plugin 'talk-plugin-okta-auth' from 'C:\talk\plugins\talk-plugin-okta-auth\index.js' +8ms
plugins-talk-plugin-okta-auth | calling plugin/update-user
(node:25548) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs","level":30,"msg":"Setup is not currently available, migrations now being checked","time":"2019-04-26T12:50:13.972Z","src":{"file":"C:\\talk\\serve.js","line":102,"func":"serve"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs","level":30,"msg":"Migrations do not have to be run","time":"2019-04-26T12:50:13.997Z","src":{"file":"C:\\talk\\serve.js","line":119,"func":"serve"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs","level":30,"taskName":"mailer","msg":"Starting job","time":"2019-04-26T12:50:14.015Z","src":{"file":"C:\\talk\\jobs\\index.js","line":15,"func":"Object.entries.forEach"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs:mailer","level":40,"msg":"Sending email is not enabled because required configuration is not available","time":"2019-04-26T12:50:14.017Z","src":{"file":"C:\\talk\\jobs\\mailer.js","line":138,"func":"module.exports"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs","level":30,"taskName":"scraper","msg":"Starting job","time":"2019-04-26T12:50:14.018Z","src":{"file":"C:\\talk\\jobs\\index.js","line":15,"func":"Object.entries.forEach"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs:scraper","level":30,"taskName":"scraper","msg":"Now processing jobs","time":"2019-04-26T12:50:14.019Z","src":{"file":"C:\\talk\\jobs\\scraper\\index.js","line":23,"func":"module.exports"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"graph:context","traceID":"3ae42714-8ce9-4e97-b630-0ccc5073acd2","level":30,"msg":"no more users are scheduled for deletion","time":"2019-04-26T12:50:14.032Z","src":{"file":"C:\\talk\\plugins\\talk-plugin-profile-data\\server\\connect.js","line":74,"func":"onTick"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs","level":30,"port":3000,"msg":"API server started","time":"2019-04-26T12:50:14.046Z","src":{"file":"C:\\talk\\serve.js","line":74,"func":"onListening"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"origin":"jobs","level":30,"port":3000,"msg":"Websocket server started","time":"2019-04-26T12:50:14.052Z","src":{"file":"C:\\talk\\serve.js","line":131,"func":"server.listen"},"v":0}
subscriptionManager is deprecated, use `execute` or `subscribe` directly from `graphql-js`!
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e6a56800-6821-11e9-8a6e-671de989e8dc","url":"/static/embed.js","method":"GET","statusCode":200,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":18,"msg":"http request","time":"2019-04-26T12:50:42.452Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e7c0ea20-6821-11e9-8a6e-671de989e8dc","url":"/embed/stream?asset_url=http%3A%2F%2Flocalhost%3A9090%2F&initialWidth=1904&childId=coral_talk_stream&parentTitle=&parentUrl=http%3A%2F%2Flocalhost%3A9090%2F","method":"GET","statusCode":200,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":91,"msg":"http request","time":"2019-04-26T12:50:44.384Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e7e08010-6821-11e9-8a6e-671de989e8dc","url":"/static/embed/stream/default.d9b7d001d27b16a3827fc04d3969da34.css","method":"GET","statusCode":200,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":7,"msg":"http request","time":"2019-04-26T12:50:44.505Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e7e2f110-6821-11e9-8a6e-671de989e8dc","url":"/static/embed/stream/bundle.968b49004b07b234ec67a5d29e4fc72b.css","method":"GET","statusCode":200,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":5,"msg":"http request","time":"2019-04-26T12:50:44.518Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e7e477b0-6821-11e9-8a6e-671de989e8dc","url":"/static/embed/stream/bundle.dbc6333c5aa9657f525d.js","method":"GET","statusCode":200,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":418,"msg":"http request","time":"2019-04-26T12:50:44.941Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
services-jwt.js | token - eyJraWQiOiItMFVURHZYQUttUW8yQzZhOTdCQ3ItREo3SkVmd3BGZGJnRnkzUEF2dnFZIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULlZ6VE16cEVkQmlZQjBkSjk3dzE4X1U5MWFwNDlRYlBSYXh6N0NrVERLN0EiLCJpc3MiOiJodHRwczovL2Rldi04NDc1MjIub2t0YXByZXZpZXcuY29tL29hdXRoMi9kZWZhdWx0IiwiYXVkIjoiYXBpOi8vZGVmYXVsdCIsImlhdCI6MTU1NjI3NDA1NCwiZXhwIjoxNTU2MzYwNDU0LCJjaWQiOiIwb2FraHUzcGZwVHlWaGwxNjBoNyIsInVpZCI6IjAwdWZ3Zzl0YmJlQ2M0Ym5oMGg3Iiwic2NwIjpbIm9wZW5pZCJdLCJzdWIiOiJicnZhbGFuZC5iY2dAZ21haWwuY29tIn0.id_FXTWGtJGL3Y3m7qULltUUJ-5UNywHgxcCGM-tCjTlGD82Ni8vnMsPswgmqpryeBHPhCqmlZkbyUoNNu5qfdY9ffdN6jAwy_w-yE9tG3aBwqdYUAvfwxkSt3vKtYGDG7oiZXyS5LXBnp1YR7rf2MZtIHQ7VbuTTIgD3VWSHnmFRi0BqT6RA5nBd8P9hbkD0oEIqTsoU53jMGK0jAfNsXq9ilav8xZi1oba9C4AaRHygmwRtOD4wFcc6TtBl3jp_Asqz8jizMC2Rd6MI6hRNZNcsF01RLwpElQ6qhN5Uy6QGLhiwS74nYhtEWN9rkToIUmnEZBbSbDmPwM_CAAz7A
services-jwt.js | kid -0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY is available.
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e85b7c70-6821-11e9-8a6e-671de989e8dc","url":"/api/v1/auth","method":"GET","statusCode":204,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":5,"msg":"http request","time":"2019-04-26T12:50:45.308Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
services-jwt.js | token - eyJraWQiOiItMFVURHZYQUttUW8yQzZhOTdCQ3ItREo3SkVmd3BGZGJnRnkzUEF2dnFZIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULlZ6VE16cEVkQmlZQjBkSjk3dzE4X1U5MWFwNDlRYlBSYXh6N0NrVERLN0EiLCJpc3MiOiJodHRwczovL2Rldi04NDc1MjIub2t0YXByZXZpZXcuY29tL29hdXRoMi9kZWZhdWx0IiwiYXVkIjoiYXBpOi8vZGVmYXVsdCIsImlhdCI6MTU1NjI3NDA1NCwiZXhwIjoxNTU2MzYwNDU0LCJjaWQiOiIwb2FraHUzcGZwVHlWaGwxNjBoNyIsInVpZCI6IjAwdWZ3Zzl0YmJlQ2M0Ym5oMGg3Iiwic2NwIjpbIm9wZW5pZCJdLCJzdWIiOiJicnZhbGFuZC5iY2dAZ21haWwuY29tIn0.id_FXTWGtJGL3Y3m7qULltUUJ-5UNywHgxcCGM-tCjTlGD82Ni8vnMsPswgmqpryeBHPhCqmlZkbyUoNNu5qfdY9ffdN6jAwy_w-yE9tG3aBwqdYUAvfwxkSt3vKtYGDG7oiZXyS5LXBnp1YR7rf2MZtIHQ7VbuTTIgD3VWSHnmFRi0BqT6RA5nBd8P9hbkD0oEIqTsoU53jMGK0jAfNsXq9ilav8xZi1oba9C4AaRHygmwRtOD4wFcc6TtBl3jp_Asqz8jizMC2Rd6MI6hRNZNcsF01RLwpElQ6qhN5Uy6QGLhiwS74nYhtEWN9rkToIUmnEZBbSbDmPwM_CAAz7A
services-jwt.js | kid -0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY is available.
(node:25548) DeprecationWarning: collection.count is deprecated, and will be removed in a future version. Use collection.countDocuments or collection.estimatedDocumentCount instead
{"name":"talk","version":"4.8.3","hostname":"LON-61652153","pid":25548,"level":30,"traceID":"e870d930-6821-11e9-8a6e-671de989e8dc","url":"/api/v1/graph/ql","method":"POST","statusCode":200,"userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36","responseTime":130,"msg":"http request","time":"2019-04-26T12:50:45.574Z","src":{"file":"C:\\talk\\middleware\\logging.js","line":20,"func":"res.end"},"v":0}
services-jwt.js | token - eyJraWQiOiItMFVURHZYQUttUW8yQzZhOTdCQ3ItREo3SkVmd3BGZGJnRnkzUEF2dnFZIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULlZ6VE16cEVkQmlZQjBkSjk3dzE4X1U5MWFwNDlRYlBSYXh6N0NrVERLN0EiLCJpc3MiOiJodHRwczovL2Rldi04NDc1MjIub2t0YXByZXZpZXcuY29tL29hdXRoMi9kZWZhdWx0IiwiYXVkIjoiYXBpOi8vZGVmYXVsdCIsImlhdCI6MTU1NjI3NDA1NCwiZXhwIjoxNTU2MzYwNDU0LCJjaWQiOiIwb2FraHUzcGZwVHlWaGwxNjBoNyIsInVpZCI6IjAwdWZ3Zzl0YmJlQ2M0Ym5oMGg3Iiwic2NwIjpbIm9wZW5pZCJdLCJzdWIiOiJicnZhbGFuZC5iY2dAZ21haWwuY29tIn0.id_FXTWGtJGL3Y3m7qULltUUJ-5UNywHgxcCGM-tCjTlGD82Ni8vnMsPswgmqpryeBHPhCqmlZkbyUoNNu5qfdY9ffdN6jAwy_w-yE9tG3aBwqdYUAvfwxkSt3vKtYGDG7oiZXyS5LXBnp1YR7rf2MZtIHQ7VbuTTIgD3VWSHnmFRi0BqT6RA5nBd8P9hbkD0oEIqTsoU53jMGK0jAfNsXq9ilav8xZi1oba9C4AaRHygmwRtOD4wFcc6TtBl3jp_Asqz8jizMC2Rd6MI6hRNZNcsF01RLwpElQ6qhN5Uy6QGLhiwS74nYhtEWN9rkToIUmnEZBbSbDmPwM_CAAz7A
services-jwt.js | kid -0UTDvXAKmQo2C6a97BCr-DJ7JEfwpFdbgFy3PAvvqY is available.
brvaland commented 5 years ago

Apologizes it is now working fine. it was my bad type RSA256 instead RS256.

On my test client i get a prompt to add an email address, insert and confirm password. I am using SSO so I should not be required to setup password.

I have updated tokenUserNotFound as in okta username is same as email address.

tokenUserNotFound: async ({ jwt }) => {
    debug('The jwt is ' + JSON.stringify(jwt));
    console.log('The jwt is ' + JSON.stringify(jwt));

    // Since the JWT has already been validated we can pass it's claims directly to upsertExternalUser
    const user = await Users.upsertExternalUser(
      null,
      jwt.sub,
      jwt.iss,
      //jwt.username
      jwt.sub
    );

    // Persisting email address in Talk is required only if sending notifications from Talk.
    // If email was included on the JWT we can add it to a "local" profile
    // and push that into the user's Profiles array.
    // To avoid duplication of Profiles, you may want add a check if user.wasUpserted
    // upsertExternalUser above will also create a profile as: { provider:jwt.iss, id:jwt.sub }

    //const email = jwt.email.toLowerCase();
    const email = jwt.sub.toLowerCase();
    user.profiles.push({
      provider: 'local',
      id: email,
    });

    // Then handle any additional User fields that you'd like to persist in Talk
    // In this example a "memberSince" claim containing a unix timestamp on the jwt
    // is used to overwrite created_at date
    // You can use the User.metadata property to store additional custom user details
    user.created_at = Date.now();

    // Finally, save and return the User that was created
    await user.save();
    debug('The user created is ' + JSON.stringify(user));
    return user;
  }
wyattjoh commented 5 years ago

It isn't highlighted well, but you should disable the following plugins to support SSO:

talk-plugin-auth
talk-plugin-local-auth
brvaland commented 5 years ago

thanks it works fine now.

I have change password option in my profile > settings. Is there a way to remove it as not sure if it is required for SSO.?

wyattjoh commented 5 years ago

Are you sure you've removed those options from the client? The change password UI lives exclusively in the talk-plugin-local-auth and talk-plugin-auth plugins.

brvaland commented 5 years ago

@wyattjoh Thanks - it works now. I missed to remove talk-plugin-local-auth from client section.

With reference to key rotation that is not supported in v4. Can i update key programmatically via a plugins if the kid is not found in TALK_JWT_SECRETS? I have checked okta it have api to get the current keys - https://developer.okta.com/docs/api/resources/oidc/#keys

Let me know your thoughts ?

wyattjoh commented 5 years ago

Unfortunately not, you can orchestrate outside of Talk to rotate the keys and restart the Talk server, but Talk currently does not support rotating keys at runtime or via API's.

Closing as it seems your primary issue is resolved.