NPM and JSVM, custom basic-auth plugin more details?

So, my API definition JSON config is in Mongo… is directly modifying it there to add the “custom_middleware” block advised if I am using the dashboard to manage/create the API? Or import/export the config after editing it?

Part of what I am doing is evaluating this for use by non-developers in a “hybrid” setup so I need to understand the Tyk recommended procedure for doing such a thing.

I tried this method by adding an “auth” folder under my path on the gateway but it does not seem to work…is this not supported? (my middleware IS invoked if in “pre”) https://tyk.io/docs/customise-tyk/plugins/javascript-middleware/install-middleware/tyk-hybrid/

I’m just running the Docker quickstart: https://github.com/TykTechnologies/tyk_quickstart/blob/master/docker-compose.yml

Actually cancel that, the “/auth/myAuth.js” was invoked after changing the “Authentication mode” in the dashboard for the API to be “Use Custom Auth (plugin)”

Ok so here is what I have, honestly I feel like the docs are not complete or I am missing something as things are just not tying together for me.

a) My API definition:

{
    "id": "5970bd3ae4b3480001d6a0e0",
    "name": "MY Auth",
    "slug": "my/auth/10",
    "api_id": "06ca7b5dfbaf4d2d59a2eaa81cf8ca1c",
    "org_id": "596cc1d5e4b3480001d6a0d9",
    "use_keyless": false,
    "use_oauth2": false,
    "use_openid": false,
    "openid_options": {
        "providers": [],
        "segregate_by_client": false
    },
    "oauth_meta": {
        "allowed_access_types": [],
        "allowed_authorize_types": [],
        "auth_login_redirect": ""
    },
    "auth": {
        "use_param": false,
        "param_name": "",
        "use_cookie": false,
        "cookie_name": "",
        "auth_header_name": ""
    },
    "use_basic_auth": false,
    "enable_jwt": false,
    "use_standard_auth": false,
    "enable_coprocess_auth": true,
    "jwt_signing_method": "",
    "jwt_source": "",
    "jwt_identity_base_field": "",
    "jwt_client_base_field": "",
    "jwt_policy_field_name": "",
    "notifications": {
        "shared_secret": "",
        "oauth_on_keychange_url": ""
    },
    "enable_signature_checking": false,
    "hmac_allowed_clock_skew": -1,
    "base_identity_provided_by": "",
    "definition": {
        "location": "header",
        "key": "x-api-version"
    },
    "version_data": {
        "not_versioned": true,
        "versions": {
            "Default": {
                "name": "Default",
                "expires": "",
                "paths": {
                    "ignored": [],
                    "white_list": [],
                    "black_list": []
                },
                "use_extended_paths": true,
                "extended_paths": {},
                "global_headers": {},
                "global_headers_remove": [],
                "global_size_limit": 0,
                "override_target": ""
            }
        }
    },
    "uptime_tests": {
        "check_list": [],
        "config": {
            "expire_utime_after": 0,
            "service_discovery": {
                "use_discovery_service": false,
                "query_endpoint": "",
                "use_nested_query": false,
                "parent_data_path": "",
                "data_path": "",
                "port_data_path": "",
                "target_path": "",
                "use_target_list": false,
                "cache_timeout": 60,
                "endpoint_returns_list": false
            },
            "recheck_wait": 0
        }
    },
    "proxy": {
        "preserve_host_header": false,
        "listen_path": "/my/auth/10",
        "target_url": "http://192.168.0.148:9080/service/authws",
        "strip_listen_path": true,
        "enable_load_balancing": false,
        "target_list": [],
        "check_host_against_uptime_tests": false,
        "service_discovery": {
            "use_discovery_service": false,
            "query_endpoint": "",
            "use_nested_query": false,
            "parent_data_path": "",
            "data_path": "hostname",
            "port_data_path": "port",
            "target_path": "/api-slug",
            "use_target_list": false,
            "cache_timeout": 60,
            "endpoint_returns_list": false
        }
    },
    "disable_rate_limit": false,
    "disable_quota": false,
    "custom_middleware": {
        "pre": [],
        "post": [],
        "post_key_auth": [],
        "auth_check": {
            "name": "myAuth",
            "path": "middleware/myAuth.js",
            "require_session": false
        },
        "response": [],
        "driver": "",
        "id_extractor": {
            "extract_from": "header",
            "extract_with": "value",
            "extractor_config": {
                "header_name": "Authorization"
            }
        }
    },
    "custom_middleware_bundle": "",
    "cache_options": {
        "cache_timeout": 60,
        "enable_cache": true,
        "cache_all_safe_requests": false,
        "cache_response_codes": [],
        "enable_upstream_cache_control": false
    },
    "session_lifetime": 1,
    "active": true,
    "auth_provider": {
        "name": "",
        "storage_engine": "",
        "meta": {}
    },
    "session_provider": {
        "name": "",
        "storage_engine": "",
        "meta": null
    },
    "event_handlers": {
        "events": {}
    },
    "enable_batch_request_support": false,
    "enable_ip_whitelisting": false,
    "allowed_ips": [],
    "dont_set_quota_on_create": false,
    "expire_analytics_after": 0,
    "response_processors": [],
    "CORS": {
        "enable": false,
        "allowed_origins": [],
        "allowed_methods": [],
        "allowed_headers": [],
        "exposed_headers": [],
        "allow_credentials": false,
        "max_age": 24,
        "options_passthrough": false,
        "debug": false
    },
    "domain": "",
    "do_not_track": false,
    "tags": [],
    "enable_context_vars": false
}

b) My plugin (under middleware/myAuth.js) on the gateway node

log("====> myAuth Auth initialising");

var myAuth = new TykJS.TykMiddleware.NewMiddleware({});

myAuth.NewProcessRequest(function(request, session) {
    log("----> Running myAuth JSVM Auth Middleware");

        var rawAuthorization = request.Headers["Authorization"];

		log("session= " + JSON.stringify(session));

        if (rawAuthorization && rawAuthorization.length > 0) {
                rawAuthorization = rawAuthorization[0];
        } else {
                request.ReturnOverrides.ResponseCode = 401;
        request.ReturnOverrides.ResponseError = 'Authentication required';
        return myAuth.ReturnData(request, {});
        }


        log(rawAuthorization);

        var newRequest = {
                "Method": "GET",
                "Body": "",
                "Headers": {
                        "Authorization":rawAuthorization,
                 },
                "Domain": "http://192.168.0.148:9080",
                "Resource": "/auth/util/doit"
        };
        
        var resp = TykMakeHttpRequest(JSON.stringify(newRequest));

        var respObj = JSON.parse(resp);

        log(respObj.Code);

        if (respObj.Code != 200) {
            request.ReturnOverrides.ResponseCode = 401;
            request.ReturnOverrides.ResponseError = 'MY Auth Failed: ' + respObj.code;
            return myAuth.ReturnData(request, {});
        }


        var newSession = {
                        "allowance": 100,
                        "rate": 100,
                        "per": 1,
                        "quota_max": -1,
                        "quota_renews": 1406121006,
                        "access_rights": {}
                };

    return myAuth.ReturnAuthData(request, newSession);
});

// Ensure init with a post-declaration log message
log("====> myAuth initialised");

c) My first request to the endpoint, I get through w/ a valid Authorization header (i.e. the plugin hits my backend auth API ok) and this is logged

2017-07-20T14:35:21.391318719Z time="Jul 20 14:35:21" level=info msg="----> Running myAuth JSVM Auth Middleware" type=log-msg
2017-07-20T14:35:21.391853783Z time="Jul 20 14:35:21" level=info msg="session= {\"access_rights\":null,\"alias\":\"\",\"allowance\":0,\"apply_policy_id\":\"\",\"basic_auth_data\":{\"hash_type\":\"\",\"password\":\"\"},\"data_expires\":0,\"enable_detail_recording\":false,\"expires\":0,\"hmac_enabled\":false,\"hmac_string\":\"\",\"id_extractor_deadline\":0,\"is_inactive\":false,\"jwt_data\":{\"secret\":\"\"},\"last_check\":0,\"last_updated\":\"\",\"meta_data\":null,\"monitor\":{\"trigger_limits\":null},\"oauth_client_id\":\"\",\"oauth_keys\":null,\"org_id\":\"\",\"per\":0,\"quota_max\":0,\"quota_remaining\":0,\"quota_renewal_rate\":0,\"quota_renews\":0,\"rate\":0,\"session_lifetime\":0,\"tags\":null}" type=log-msg
2017-07-20T14:35:21.391925198Z time="Jul 20 14:35:21" level=info msg="Basic XXXX==" type=log-msg
2017-07-20T14:35:22.474491045Z time="Jul 20 14:35:22" level=info msg=200 type=log-msg

d) My 2nd request to the endpoint (i would expect session to be populated now?) But its not, just looks like another empty one (logs below)

2017-07-20T14:35:40.263778912Z time="Jul 20 14:35:40" level=info msg="----> Running myAuth JSVM Auth Middleware" type=log-msg
2017-07-20T14:35:40.264316972Z time="Jul 20 14:35:40" level=info msg="session= {\"access_rights\":null,\"alias\":\"\",\"allowance\":0,\"apply_policy_id\":\"\",\"basic_auth_data\":{\"hash_type\":\"\",\"password\":\"\"},\"data_expires\":0,\"enable_detail_recording\":false,\"expires\":0,\"hmac_enabled\":false,\"hmac_string\":\"\",\"id_extractor_deadline\":0,\"is_inactive\":false,\"jwt_data\":{\"secret\":\"\"},\"last_check\":0,\"last_updated\":\"\",\"meta_data\":null,\"monitor\":{\"trigger_limits\":null},\"oauth_client_id\":\"\",\"oauth_keys\":null,\"org_id\":\"\",\"per\":0,\"quota_max\":0,\"quota_remaining\":0,\"quota_renewal_rate\":0,\"quota_renews\":0,\"rate\":0,\"session_lifetime\":0,\"tags\":null}" type=log-msg
2017-07-20T14:35:40.264381096Z time="Jul 20 14:35:40" level=info msg="Basic XXXX==" type=log-msg
2017-07-20T14:35:40.950387636Z time="Jul 20 14:35:40" level=info msg=200 type=log-msg

e) Assuming a session would be established after the FIRST successful invocation, and the session key properly based on the Authorization header per the “id_extractor” config… will Tyk still call the auth plugin on every invocation and it is up to my plugin to determine (based on something in the session) if it should call back again to the auth endpoint? OR will tyk upon seeing a valid session SKIP calling my plugin, and only call again when the key expires.

Perhaps something is still missing in my config?

This is where the bundles come in, with a bundle you just specify the bundle ID in the dashboard and it gets downloaded, validated and installed for you without having to add stuff manually.

The dashboard doesn’t support adding the block manually, you would need to use the rest api.

or use a bundle… which is he simplest method.

For your other questions I’ve handed over to our plugin expert, he’ll respond shortly.

thanks!

Yes I’ll eventually get to the bundled packaging, for now I’m just trying to get something working to prove it out as part of this eval. Its definitely being invoked, just the session part I’m hung/blocked by right now as described above in my last post

Hi @bitsofinfo, I’m currently reviewing your settings!

FYI, just upgraded to the latest of the docker quickstart which is showing 1.3.7 (but same result, seeing auth plugin continually re-invoked)

Hi @bitsofinfo, the ID extractor isn’t currently available for JS middleware as we’re still migrating it to our rich plugin architecture.

I suggest following up with the simplest solution which it’s to use a Pre middleware and cover some of the ID extractor logic right there:

    var authMiddleware = new TykJS.TykMiddleware.NewMiddleware({});

    function authenticate(token) {
        log("Calling the backend")
        // Do the TykMakeHttpRequest logic here:
        return token == "fa1b865d9280d4a488afa30fd60216e7"
    }

    authMiddleware.NewProcessRequest(function(request,session,conf) {

        token = request.Headers["Authorization"]

        var session = JSON.parse(TykGetKeyData(token))
        if (session.status == "error") {
            log("Session not found, hitting the backend")
            var valid = authenticate(token)
            if(!valid) {
                request.ReturnOverrides.ResponseCode = 401;
                request.ReturnOverrides.ResponseError = "Failed auth"
                return authMiddleware.ReturnData(request, {})
            }
            session = {
                            "allowance": 100,
                            "rate": 100,
                            "per": 1,
                            "quota_max": -1,
                            "quota_renews": 1406121006,
                            "access_rights": {}
                    };
            TykSetKeyData(token, JSON.stringify(session), "0")
            return authMiddleware.ReturnData(request, {});
        }

        return authMiddleware.ReturnData(request, {});
    });

The calls to TykGetKeyData and TykSetKeyData covers the ID extractor functionality in this case, you should replace the authenticate function with your own logic.

The API definition custom middleware block will look like this:

    "custom_middleware": {
      "pre": [{
        "name": "authMiddleware",
        "path": "middleware/authMiddleware.js"
      }]
    },

Best regards.

Thanks @matiasb

So here is my updated plugin, I changed it from “auth_check” to “pre” as you noted.

Here is the log from the updated code below when invoked. The key error being “Master keys disallowed in configuration, key not added.” after my auth endpoint is successfully invoked and it tryes to set the key

2017-07-24T14:04:28.399589698Z time="Jul 24 14:04:28" level=warning msg="Failed to retrieve key detail." err="not found" key="****Iw==" status=fail
2017-07-24T14:04:28.399829778Z time="Jul 24 14:04:28" level=info msg="No session exists, attempting auth and creating" type=log-msg
2017-07-24T14:04:29.018437419Z time="Jul 24 14:04:29" level=info msg=200 type=log-msg
2017-07-24T14:04:29.018559040Z time="Jul 24 14:04:29" level=error msg="Master keys disallowed in configuration, key not added."
2017-07-24T14:04:29.025426429Z time="Jul 24 14:04:29" level=error msg="Failed to decode middleware request data on return from VM: invalid character 'u' looking for beginning of value"

log("====> myAuth Auth initialising");

var myAuth = new TykJS.TykMiddleware.NewMiddleware({});

myAuth.NewProcessRequest(function(request, session, config) {
    log("----> Running myAuth JSVM Auth Middleware");
    
    log("config= " + JSON.stringify(config));

    log("session= " + JSON.stringify(session));

    log("request= " + JSON.stringify(request));

        var rawAuthorization = request.Headers["Authorization"];

        if (rawAuthorization && rawAuthorization.length > 0) {
            rawAuthorization = rawAuthorization[0];
        } else {
            request.ReturnOverrides.ResponseCode = 401;
        	request.ReturnOverrides.ResponseError = 'Authentication required';
        	return myAuth.ReturnData(request, {});
        }


        log(rawAuthorization);
        
        var session = JSON.parse(TykGetKeyData(rawAuthorization))
        
        if (session.status == "error") {

			log("No session exists, attempting auth and creating");
			
			var newRequest = {
					"Method": "GET",
					"Body": "",
					"Headers": {
							"Authorization":rawAuthorization
					 },
					"Domain": "http://192.168.0.148:9080",
					"Resource": "/auth/util/xxxx"
			};

			var resp = TykMakeHttpRequest(JSON.stringify(newRequest));

			var respObj = JSON.parse(resp);

			log(respObj.Code);

			if (respObj.Code != 200) {
				request.ReturnOverrides.ResponseCode = 401;
				request.ReturnOverrides.ResponseError = 'MY Auth Failed: ' + respObj.code;
				return myAuth.ReturnData(request, {});
			}
			
			session = {
                            "allowance": 100,
                            "rate": 100,
                            "per": 1,
                            "quota_max": -1,
                            "quota_renews": 1406121006,
                            "access_rights": {}
                    };
                    
            TykSetKeyData(rawAuthorization, JSON.stringify(session), "0");
            return myAuth.ReturnData(request, {});
			
		} else {
			log("Pre-existing session exists... using, no MY auth check");
		}

    return myAuth.ReturnData(request, {});
});

// Ensure init with a post-declaration log message
log("====> myAuth initialised");

So I added “allow_master_keys” true, in the gateway tyk.conf file, now I get this. Looks like the key is being updated in Tyk, but now I get

"Session state is missing or unset! Please make sure that auth headers are properly applied."

2017-07-24T14:14:42.490281990Z time="Jul 24 14:14:42" level=warning msg="Failed to retrieve key detail." err="not found" key="****Iw==" status=fail
2017-07-24T14:14:42.490329969Z time="Jul 24 14:14:42" level=info msg="No session exists, attempting auth and creating" type=log-msg
2017-07-24T14:14:43.705279246Z time="Jul 24 14:14:43" level=info msg=200 type=log-msg
2017-07-24T14:14:43.705368576Z time="Jul 24 14:14:43" level=warning msg="No API Access Rights set, adding key to ALL."
2017-07-24T14:14:43.705386384Z time="Jul 24 14:14:43" level=info msg="Reset quota for key." inbound-key="****Iw==" key=quota-24edb24c
2017-07-24T14:14:43.705395856Z time="Jul 24 14:14:43" level=info msg="Reset quota for key." inbound-key="****Iw==" key=quota-24edb24c
2017-07-24T14:14:43.705791609Z time="Jul 24 14:14:43" level=info msg="Reset quota for key." inbound-key="****Iw==" key=quota-24edb24c
2017-07-24T14:14:43.705851971Z time="Jul 24 14:14:43" level=info msg="Reset quota for key." inbound-key="****Iw==" key=quota-24edb24c
2017-07-24T14:14:43.705869363Z time="Jul 24 14:14:43" level=info msg="Key added or updated." api_id=-- expires=0 key="****Iw==" org_id= path=-- server_name=system user_id=system user_ip=--
2017-07-24T14:14:43.712565120Z time="Jul 24 14:14:43" level=error msg="Failed to decode middleware request data on return from VM: invalid character 'u' looking for beginning of value"
2017-07-24T14:14:43.712639795Z time="Jul 24 14:14:43" level=error msg="request error: Session state is missing or unset! Please make sure that auth headers are properly applied." api_id=8c685ec987cf4fc16cef3d7cf2683a22 org_id=5975fbce52d58f000138b93f path="/" server_name="http://192.168.0.148:9080/test/auth" user_id= user_ip=172.18.0.1

Hi @bitsofinfo, looks like there’s a JS error somewhere, note the Failed to decode middleware request data on return from VM error.

Yeah I’ve looked for that but I’m not seeing what it is (pasted code above)

I mean this line executes as I see its log output from tyk “key added or updated”

TykSetKeyData(rawAuthorization, JSON.stringify(session), "0");

So whats wrong w/ this line?

return myAuth.ReturnData(request, {});

I’ve even added a try/catch around the return block and no error is thrown, I log the output of the call to “ReturnData” before returning and I get this below. I then just return it, then that log line appears, so I have no clue what is generating that undefined error other than whatever is invoking my function?

{\"Request\":{\"AddParams\":{},\"Body\":\"\",\"DeleteHeaders\":[],\"DeleteParams\":[],\"ExtendedParams\":{},\"Headers\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-US,en;q=0.8,pt;q=0.6\"],\"Authorization\":[\"Basic xxxxx==\"],\"Cache-Control\":[\"max-age=0\"],\"Connection\":[\"keep-alive\"],\"Cookie\":[\"csrf_token=mwtnbNEb56sH7RjlK0FaoBlFppL2fgjaaAZzWbl+hHc=; authorisation=xxxxx-d084-432d-6324-abccd88c8fcd\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36\"]},\"IgnoreBody\":false,\"Params\":{\"wsdl\":[\"\"]},\"ReturnOverrides\":{\"ResponseCode\":0,\"ResponseError\":\"\"},\"SetHeaders\":{},\"URL\":\"/ocd/auth/10\"},\"SessionMeta\":{}}" type=log-msg

@matiasb

I am at a loss as to what is causing that undefined (note the log statements following this dumbed down JS middleware snippet)

log("====> myAuth Auth initialising");

var myAuth = new TykJS.TykMiddleware.NewMiddleware({});

myAuth.NewProcessRequest(function(request, session, config) {

    log("----> Running myAuth JSVM Auth Middleware");
    
    log("config= " + JSON.stringify(config));

    log("session= " + JSON.stringify(session));

    log("request= " + JSON.stringify(request));

        var rawAuthorization = request.Headers["Authorization"];

        if (rawAuthorization && rawAuthorization.length > 0) {
            rawAuthorization = rawAuthorization[0];
        } else {
            request.ReturnOverrides.ResponseCode = 401;
        	request.ReturnOverrides.ResponseError = 'Authentication required';
        	return myAuth.ReturnData(request, {});
        }


        log(rawAuthorization);
        
        var session = JSON.parse(TykGetKeyData(rawAuthorization))
        
        if (session.status == "error") {

			log("No session exists, attempting auth (fake) and creating");

			session = {
                            "allowance": 100,
                            "rate": 100,
                            "per": 1,
                            "quota_max": -1,
                            "quota_renews": 1406121006,
                            "access_rights": {}
                    };
			
			log("6");
            TykSetKeyData(rawAuthorization, JSON.stringify(session), "0");
            
    		log("7");
    	    return myAuth.ReturnData(request,{});
			
		} else {
			log("Pre-existing session exists... using, no MY auth check");
			log("8");
			
			try {
		    	var x = myAuth.ReturnData(request,{});
		    	log("9");
		    	log(JSON.stringify(x));
		    	log("10");
		    	return x;
		    	
		    } catch(e) {
		    	log(JSON.stringify(e));
		    }
		}

});

// Ensure init with a post-declaration log message
log("====> myAuth initialised");



2017-07-24T19:29:09.280516100Z time="Jul 24 19:29:09" level=info msg="----> Running myAuth JSVM Auth Middleware" type=log-msg
2017-07-24T19:29:09.281039200Z time="Jul 24 19:29:09" level=info msg="config= {\"config_data\":{\"foo\":\"bar\"}}" type=log-msg
2017-07-24T19:29:09.282068700Z time="Jul 24 19:29:09" level=info msg="session= {\"access_rights\":null,\"alias\":\"\",\"allowance\":0,\"apply_policy_id\":\"\",\"basic_auth_data\":{\"hash_type\":\"\",\"password\":\"\"},\"data_expires\":0,\"enable_detail_recording\":false,\"expires\":0,\"hmac_enabled\":false,\"hmac_string\":\"\",\"id_extractor_deadline\":0,\"is_inactive\":false,\"jwt_data\":{\"secret\":\"\"},\"last_check\":0,\"last_updated\":\"\",\"meta_data\":null,\"monitor\":{\"trigger_limits\":null},\"oauth_client_id\":\"\",\"oauth_keys\":null,\"org_id\":\"\",\"per\":0,\"quota_max\":0,\"quota_remaining\":0,\"quota_renewal_rate\":0,\"quota_renews\":0,\"rate\":0,\"session_lifetime\":0,\"tags\":null}" type=log-msg
2017-07-24T19:29:09.282483400Z time="Jul 24 19:29:09" level=info msg="request= {\"AddParams\":{},\"Body\":\"\",\"DeleteHeaders\":[],\"DeleteParams\":[],\"ExtendedParams\":{},\"Headers\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-US,en;q=0.8,pt;q=0.6\"],\"Authorization\":[\"Basic xxx==\"],\"Cache-Control\":[\"max-age=0\"],\"Connection\":[\"keep-alive\"],\"Cookie\":[\"csrf_token=mwtnbNEb56sH7RjlK0FaoBlFppL2fgjaaAZzWbl+hHc=; authorisation=8302fb04-f44f-434d-6d0c-c21dd2656c54\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36\"]},\"IgnoreBody\":false,\"Params\":{\"wsdl\":[\"\"]},\"ReturnOverrides\":{\"ResponseCode\":0,\"ResponseError\":\"\"},\"SetHeaders\":{},\"URL\":\"/my/auth/10\"}" type=log-msg
2017-07-24T19:29:09.283081200Z time="Jul 24 19:29:09" level=info msg="Basic xxx==" type=log-msg
2017-07-24T19:29:09.284802700Z time="Jul 24 19:29:09" level=info msg="Retrieved key detail." key="****Iw==" status=ok
2017-07-24T19:29:09.284848800Z time="Jul 24 19:29:09" level=info msg="Pre-existing session exists... using, no MY auth check" type=log-msg
2017-07-24T19:29:09.284864800Z time="Jul 24 19:29:09" level=info msg=8 type=log-msg
2017-07-24T19:29:09.285206900Z time="Jul 24 19:29:09" level=info msg=9 type=log-msg
2017-07-24T19:29:09.285592100Z time="Jul 24 19:29:09" level=info msg="{\"Request\":{\"AddParams\":{},\"Body\":\"\",\"DeleteHeaders\":[],\"DeleteParams\":[],\"ExtendedParams\":{},\"Headers\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-US,en;q=0.8,pt;q=0.6\"],\"Authorization\":[\"Basic xxx==\"],\"Cache-Control\":[\"max-age=0\"],\"Connection\":[\"keep-alive\"],\"Cookie\":[\"csrf_token=mwtnbNEb56sH7RjlK0FaoBlFppL2fgjaaAZzWbl+hHc=; authorisation=8302fb04-f44f-434d-6d0c-c21dd2656c54\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36\"]},\"IgnoreBody\":false,\"Params\":{\"wsdl\":[\"\"]},\"ReturnOverrides\":{\"ResponseCode\":0,\"ResponseError\":\"\"},\"SetHeaders\":{},\"URL\":\"/my/auth/10\"},\"SessionMeta\":{}}" type=log-msg
2017-07-24T19:29:09.285655500Z time="Jul 24 19:29:09" level=info msg=10 type=log-msg
2017-07-24T19:29:09.289640900Z time="Jul 24 19:29:09" level=error msg="Failed to decode middleware request data on return from VM: invalid character 'u' looking for beginning of value"
2017-07-24T19:29:09.289697800Z time="Jul 24 19:29:09" level=error msg="request error: Session state is missing or unset! Please make sure that auth headers are properly applied." api_id=8c685ec987cf4fc16cef3d7cf2683a22 org_id=5975fbce52d58f000138b93f path="/" server_name="http://192.168.0.148:9080/service/xxx" user_id= user_ip=172.18.0.1

I think this is solved, the issue was the auth type on the API.

Was set to auth plugin, when I changed it to “keyless” now it seems to work when using the “pre” middleware instead of “auth_check”

I would suggest:

  1. Changing your auth mechanism to “Auth Token” and set the location of the token to use the Header x-internal-authorization
  2. In your plugin, hash the rawAuthorization string
  3. Use the hash as the key for the session (or, if you want to go a step further, use orgID+hash(rawAuthorization))
  4. Add the hash as an x-internal-authorization header

Reasoning:

  1. Open API’s do not process rate limits or quotas
  2. Open APIs, since there is no token, do not collect analytics per user
  3. It means you can modify the session from the dashboard (if you use the orgID as a prefix)

I would also strongly suggest turning off master keys, it basically means that the inbound session has access to ALL APIs if the access list is empty. This might be ok for a PoC, but it’s not a safe mode.

M.

Thanks

Changing your auth mechanism to “Auth Token” and set the location of the token to use the Header x-internal-authorization

Does this mean that the actual external CLIENT of my API must set this? Or that my PRE middleware JS can set it, prior to any of the auth token management in the gateway runs?

In your plugin, hash the rawAuthorization string

What hash function would you recommend, or are available w/ the JSVM env? Also this key is stored in redis correct, so without a secure hash, potentially their credentials would be exposed in redis to anyone with access to it, correct?

Use the hash as the key for the session (or, if you want to go a step further, use orgID+hash(rawAuthorization))

How can I get the apiId and orgId from within one of these JSVM middleware functions?

Add the hash as an x-internal-authorization header

I assume you mean like request.SetHeaders = { "x-internal-authorization" : authHash };

I would also strongly suggest turning off master keys, it basically means that the inbound session has access to ALL APIs if the access list is empty. This might be ok for a PoC, but it’s not a safe mode.

Makes sense, do you have an example of the proper structure I can use to set this dynamically on that session object that I return? The one’s I’ve seen seem to require an id/uuid, which… doesn’t pre-exist etc?

Your PRE middleware should set it, since it is a pre-processor, the header will carry through to the Tyk auth token middleware

There’s no hash available in the env, so you may need to use a pre-baked one like this one liner

If you have enable hash_keys in your tyk.conf, Tyk will secure the credentials:

hash_keys

Set this value to true to enable key hashing, this will start hashing all keys that are generated by Tyk in Redis. Enabling this means that keys that are created are only exposed once, during creation. If the key is lost or misplaced after this it will not be retrievable (however its hash can still be deleted, if known).

If this is set to true, the same value should be enabled in the Dashboard configuration so that the UI can react appropriately.

You don’t need the API ID, you can pass these values in the config_data portion of the API definition.

Correct

The ID you see is the API ID, so it would be this in the root of the session object:

        "access_rights": {
            "API_ID": {
                "api_name": "ANY NAME",
                "api_id": "API_ID",
                "versions": ["Default"],
                "allowed_urls": null
            }
        },
        "org_id": "53ac07777cbb8c2d53000002",

The api_name is for humans, so you can set it to anything. And thed API ID is the same as that in the API Definition (so you could pass it in config).

Just to complicate things, and maybe make things more controllable, you could put a dummy API ID in there (create an API with a single Mock on a whitelist for example), and then set the apply_policy_id field to a POlicy ID.

You can then manage the ACL for all tokens created by this middleware from the dashboard by editing the referenced Policy.

Great, I am doing it this way.

you would need to do that yourself or as per the suggestion in the other post, you let Tyk do it for you when you set an internal auth header.

If you have enable hash_keys in your tyk.conf, Tyk will secure the credentials:

So if this is enabled, then I DON’T need to pre-hash the key before setting it? Tyk will just do it with Murmur3 automatically when TykGetKeyData or TykSetKeyData is called w /a “cleartext” key value?

Yes, that is correct :slight_smile: