1

Using NodeJS express server to handle GOOGLE oauth via OpenID protocol on the server-side, I am trying to have the callback run this checklist after google redirects the user to the API with the auth code + in query string.

  1. Only allow emails with special domain of school to pass (This is a school project).
  2. Make exchange for Token Object containing Auth Token, Refresh Token, etc.
  3. Store Auth token via cookie
  4. Store whole token object via redis cache in JSON OBJECT... THIS IS WHERE I AM CAUGHT. (using the redis module REJSON. REJSON because user data from database can be added to object in memory for CACHING USER DATA...)
  5. Next steps in logic include checking if user exists in mongodb, creating user in mongodb if not, redirecting to browser, carrying cookie, using auth token to check against redis cache as maintaining a persistenting session... will eventually be secure via hash, httpOnly, https etc...

Hopefully that lets you in on the picture of my logic, but this is seemingly a REDIS OR REDIS RELATED MODULE ISSUE.

To use the Redis REJSON module, I am running a redis-redisjson docker image which is exposing to PORT 6379, and the express server(running on PORT 4000) is to be the client of the redis cache server...

Node module Redis-rejson allows redisJSON commands to be mapped to javascript-friendly names. And Node module Redis is a redis client library for node.

//This is a minimalist web-framework for NodeJS
var express = require("express");

//axios - handles HTTP requests
const axios = require("axios");

//redis - use for caching
//rejson - store JSON via redis
const redis = require("redis"),
      rejson = require("redis-rejson");
      rejson(redis);

//set ports
const PORT = process.env.PORT || 4000;
const REDIS_PORT = process.env.PORT || 6379;

const client = redis.createClient(REDIS_PORT);

// Init Express app 
var app = express();

  //callback route from google

 app.get("/signin/callback", (req, res, next) => {
    //declare vars from query string api return for later use
    //console.log(req.query);
    let hd = req.query.hd;
    let authCode = req.query.code;

    //Only allow GUHSD email domains
    if(hd !== 'guhsd.net') {
        console.log('you are shall not pass')
        // The return is for stopping execution of controller
        return res.redirect(301, 'http://localhost:3000/?error=invalid_domain');
    } 

    //GET client_id and client_secret FROM JSON

     //Make POST REQ to exchange AuthCode for JSON token object
     axios.post('https://oauth2.googleapis.com/token', {
        client_id: '<taken out as to not expose>',
        client_secret: '<taken out as to not expose>',
        code: authCode,
        grant_type: 'authorization_code',
        redirect_uri: 'http://localhost:4000/signin/callback'
        })
        .then((response) => {
            console.log('Your token must to be here');

            // Logic after exchange 
            //1. Start Sessions - Client HTTP only Cookie & Server Redis Cache
            //2. Check if ACC exists - if so redirect client :)
            //3. if ACC DOES NOT exist, create new acc!! then redirect client :)

            async function passOver() {
                console.log(response.data);
                    // example: 
               //  {
               //     access_token: 'ya29.a0AfH6SMBSm3D99XAhmlxHtYOVVm7gZT9h8Bd8I9RgpYPhK0qXQwGT4fuMWhDsqDpcTfQuIg6bvY-tFUISX4Wm2Is-jprW2sstjmD4hjc2cQh5uIYODg1Re6v80FKENDdEAinTm9kid0QaKiaRxJQHt1deap-Ik1mcy2s',   
               //     expires_in: 3599, 
               //     refresh_token: '1//06qroj95zjugXCgYIARAAGAYSNwF-L9IrzWEi6q0wDpeUVKmnPZYZjZpsMS-KVT4fY9NzHgZCUxgY8fg2J_Nil2vJpMz52y-2pyY',
               //     scope: 'openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
               //     token_type: 'Bearer',
               //     id_token: 'eyJhbGciOiJSUzI1NiIsImtpZCI6Ijk2MGE3ZThlODM0MWVkNzUyZjEyYjE4NmZhMTI5NzMxZmUwYjA0YzAiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTA1MzUzMTYxMjcxODg4Mjg5NjYiLCJoZCI6Imd1aHNkLm5ldCIsImVtYWlsIjoiMzMwMjk0QGd1aHNkLm5ldCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoidEhoVEl6eWp3MHcyRFpVaVpUMmxCQSIsIm5hbWUiOiJERVZJTiBQUk9WRU5DRSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vLVhTaV9oU2JsVWo0L0FBQUFBQUFBQUFJL0FBQUFBQUFBQUFBL0FNWnV1Y25HXzBwS3N0eVo3cEI0Wk0yZlpMQkNIUEU3UkEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IkRFVklOIiwiZmFtaWx5X25hbWUiOiJQUk9WRU5DRSIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNTkwNjEwODE4LCJleHAiOjE1OTA2MTQ0MTh9.Nt2eGzCsKrUmyztqYWiZ16-1S7OCRcUFlSFvhVAy9HusYfLqp0nz3diUkuP-D_27BCtBsZCQ0JC1evPISwLX9H1hJs_GKYSD12s-ovJ8S0AzghY0M-AOuYxhGvKautusmXYfHvhfcPj7IKhPo_IXBl3x-ryOtRRrpJR6c30QPl1JUae74sAcLk8H1stLgqptrrRTgJWYdTXxJHSrZcR8RsLw2aY4GwuPGEX-AD6h51IZlNTl_6qNpaIt_7mFSUV-iF1PECAotfhKHdAryZCFRBq4XE6uJnYq3WnOVAMAEYwqT543pxarXOmLuAwhDqqewyuCXsjlbyhBys-4iEhYAg'
               //   }
               //expires_in is in seconds... cookie takes milliseconds as expires arg. 

                //send to client, store in cookie(browser's session starts)

                res.cookie(
                    "tokenResponse", `${response.data.access_token}`, {
                        maxAge: `${response.data.expires_in}`
                    }
                )

              var keyObject = JSON.stringify(response.data);
              //set redis key to user
              var user = 'user';
                //store response.data in redis cache(server's session starts)
                client.json_set(user, '.', keyObject, function (err) {
                    if (err) { throw err; }
                    console.log('Set JSON at key ' + user + '.');
                    client.json_get(user, '.access_token', function (err, value) {
                      if (err) { throw err; }
                      console.log('value of .', value); //outputs JSON
                      client.quit();
                    });
                  });
                res.json(keyObject);

                //redirect from server to frontend
              //  await res.redirect('http://localhost:3000');
             }

             //call passover
             passOver();


        })
        //if err, log & redirect user to client
        .catch((error) => {
             console.log(error.request);
             console.log(error.response.data);
            return res.redirect(301, 'http://localhost:3000/?error=google_failed_exchange');
        }); 
 });

//start the express server
app.listen(4000, () =>
console.log(`App started on port ${PORT}`)
);

module.exports = app;

The err im getting is

                   if (err) { throw err; }
                               ^        

ReplyError: ERR unknown command 'json.set'
    at parseError (E:\docker-node-react-nginx\backend\node_modules\redis-parser\lib\parser.js:179:12)
    at parseType (E:\docker-node-react-nginx\backend\node_modules\redis-parser\lib\parser.js:302:14) {
  command: 'JSON.SET',
  args: [
    'user',
    '.',
    '{"access_token":"ya29.a0AfH6SMCSN3_0fXFexXYUqrkfhlJ5FmdkO-eqKeiXeSnRzlwD5aBDpBF7y-pXMDBY1YFqXLf-JU0mc5FXVo8nZER-6wB-hAm7qW_0w4Z3TcfoQfOT7ZXg8ZqK2DPyW8TnsZELWe9eDBYvFqM0lTWyWe3Z9ZqUXgv6Kz4","expires_in":3599,"refresh_token":"1//06FRrH2GkKtP2CgYIARAAGAYSNwF-L9IrnL1ZpMhxaiYWYuSnI7p6DG0uFIO3Vu2qt40Scio5SAlGT0mvBZ8hWvaPcJEEnjaunDw","scope":"https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/userinfo.profile","token_type":"Bearer","id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImZiOGNhNWI3ZDhkOWE1YzZjNjc4ODA3MWU4NjZjNmM0MGYzZmMxZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyNDM1NjY4NDcxMDItdTRkazg1Y21qcjEybWgya25ycHYzaW5zMnRjcnBzOHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTA1MzUzMTYxMjcxODg4Mjg5NjYiLCJoZCI6Imd1aHNkLm5ldCIsImVtYWlsIjoiMzMwMjk0QGd1aHNkLm5ldCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdF9oYXNoIjoiV2kwRVdlSl9fQmVsaGV1RF9SVEl6USIsIm5hbWUiOiJERVZJTiBQUk9WRU5DRSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vLVhTaV9oU2JsVWo0L0FBQUFBQUFBQUFJL0FBQUFBQUFBQUFBL0FNWnV1Y25HXzBwS3N0eVo3cEI0Wk0yZlpMQkNIUEU3UkEvczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6IkRFVklOIiwiZmFtaWx5X25hbWUiOiJQUk9WRU5DRSIsImxvY2FsZSI6ImVuIiwiaWF0IjoxNTkwNjI0NDIyLCJleHAiOjE1OTA2MjgwMjJ9.IyF5uB2ldLBQLu3CVMDpXf8szEK_BbR8SPrtdpJR_Y3bHklJ8e3JYGQT9AWjkcSy0I4DNUhkXiFk25HvZ06u2ekGd_adSknUVNwZe_N1IQTlMF1m-oqWbaRtnr4oxerQg_YunZDD4z_Lh5ecSDVz4X8H39uO7jrAvY1CdnZfZ4D2Je8aV1Zns5JahKhOTopPcy5sE1dSBNPqqGvUiY9h0MQHne9byUz9jMvog3YI-8-uexjC_JWsbzMFjE65ze5_cUpApYB5tUrNTjqvhiYgcimIPOXoto_VIHHEEoho5uHOkUQw_UVXleUa9vI77W1j7U7HnH-h_3C5ylx7UEDm6Q"}'
  ],
  code: 'ERR'
}
[nodemon] app crashed - waiting for file changes before starting...
Guy Korland
  • 9,139
  • 14
  • 59
  • 106

1 Answers1

0
import Redis from 'ioredis'
const connOpts = {
  port: process.env.REDIS_PORT,
  host: process.env.REDIS_HOST
 }
const client = new Redis(connOpts)
const sets = (id, keyPaths, input) => {
  
  return client.send_command('JSON.SET', id, keyPaths, JSON.stringify(input)).then((res) => {
    return res
  }).catch((e) => {
    console.error('redis insertion error', e)
  })
}
sets("134", ".", {"access_token":"ya29"}