Granular access for endpoints failing (allowed_urls) -> Access to this resource has been disallowed

Hello community,
We are trying to do something simple:
Create a granular access for a given path /apidemo, allow one key id to access a specific api endpoint registered at Tyk (Community).
I’m following the instructions contained at this page:
https://tyk.io/docs/security/security-policies/secure-apis-method-path/#setting-granular-paths-on-a-per-key-basis

However, once I apply the setup, I get a error message that I could not found in the forum posts.
“error”: “Access to this resource has been disallowed”

Is there anything wrong with the configuration below? We just need basic key to access an endpoint using “allowed_urls” parameter. Appreciate any help on this.

-Daniel

The only “change” done was in the key json as:

"allowed_urls": [
                {
                    "methods": ["GET"],
                    "url": "/apidemo"
                }
            ],

API Json:

{
	"name": "demoapi",
	"slug": "demoapi",
	"listen_port": 0,
	"protocol": "",
	"enable_proxy_protocol": false,
	"api_id": "2",
	"org_id": "1",
	"use_keyless": false,
	"use_oauth2": false,
	"use_openid": false,
	"openid_options": {
		"providers": null,
		"segregate_by_client": false
	},
	"oauth_meta": {
		"allowed_access_types": null,
		"allowed_authorize_types": null,
		"auth_login_redirect": ""
	},
	"auth": {
		"use_param": false,
		"param_name": "",
		"use_cookie": false,
		"cookie_name": "",
		"auth_header_name": "Authorization",
		"use_certificate": false,
		"validate_signature": false,
		"signature": {
			"algorithm": "",
			"header": "",
			"secret": "",
			"allowed_clock_skew": 0,
			"error_code": 0,
			"error_message": ""
		}
	},
	"auth_configs": null,
	"use_basic_auth": false,
	"basic_auth": {
		"disable_caching": false,
		"cache_ttl": 0,
		"extract_from_body": false,
		"body_user_regexp": "",
		"body_password_regexp": ""
	},
	"use_mutual_tls_auth": false,
	"client_certificates": null,
	"upstream_certificates": null,
	"pinned_public_keys": null,
	"enable_jwt": false,
	"use_standard_auth": false,
	"use_go_plugin_auth": false,
	"enable_coprocess_auth": false,
	"jwt_signing_method": "",
	"jwt_source": "",
	"jwt_identity_base_field": "",
	"jwt_client_base_field": "",
	"jwt_policy_field_name": "",
	"jwt_default_policies": null,
	"jwt_issued_at_validation_skew": 0,
	"jwt_expires_at_validation_skew": 0,
	"jwt_not_before_validation_skew": 0,
	"jwt_skip_kid": false,
	"jwt_scope_to_policy_mapping": null,
	"jwt_scope_claim_name": "",
	"notifications": {
		"shared_secret": "",
		"oauth_on_keychange_url": ""
	},
	"enable_signature_checking": false,
	"hmac_allowed_clock_skew": 0,
	"hmac_allowed_algorithms": null,
	"request_signing": {
		"is_enabled": false,
		"secret": "",
		"key_id": "",
		"algorithm": "",
		"header_list": null,
		"certificate_id": "",
		"signature_header": ""
	},
	"base_identity_provided_by": "",
	"definition": {
		"location": "header",
		"key": "x-api-version",
		"strip_path": false
	},
	"version_data": {
		"not_versioned": true,
		"default_version": "",
		"versions": {
			"Default": {
				"name": "v1",
				"expires": "",
				"paths": {
					"ignored": null,
					"white_list": null,
					"black_list": null
				},
				"use_extended_paths": true,
				"extended_paths": {},
				"global_headers": null,
				"global_headers_remove": null,
				"global_response_headers": null,
				"global_response_headers_remove": null,
				"ignore_endpoint_case": false,
				"global_size_limit": 0,
				"override_target": ""
			}
		}
	},
	"uptime_tests": {
		"check_list": null,
		"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": 0,
				"endpoint_returns_list": false
			},
			"recheck_wait": 0
		}
	},
	"proxy": {
		"preserve_host_header": false,
		"listen_path": "/demoapi/",
		"target_url": "http://our.host.local/",
		"disable_strip_slash": false,
		"strip_listen_path": true,
		"enable_load_balancing": false,
		"target_list": null,
		"check_host_against_uptime_tests": false,
		"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": 0,
			"endpoint_returns_list": false
		},
		"transport": {
			"ssl_insecure_skip_verify": false,
			"ssl_ciphers": null,
			"ssl_min_version": 0,
			"ssl_max_version": 0,
			"ssl_force_common_name_check": false,
			"proxy_url": ""
		}
	},
	"disable_rate_limit": false,
	"disable_quota": false,
	"custom_middleware": {
		"pre": null,
		"post": null,
		"post_key_auth": null,
		"auth_check": {
			"name": "",
			"path": "",
			"require_session": false,
			"raw_body_only": false
		},
		"response": null,
		"driver": "",
		"id_extractor": {
			"extract_from": "",
			"extract_with": "",
			"extractor_config": null
		}
	},
	"custom_middleware_bundle": "",
	"cache_options": {
		"cache_timeout": 0,
		"enable_cache": false,
		"cache_all_safe_requests": false,
		"cache_response_codes": null,
		"enable_upstream_cache_control": false,
		"cache_control_ttl_header": "",
		"cache_by_headers": null
	},
	"session_lifetime": 0,
	"active": true,
	"internal": false,
	"auth_provider": {
		"name": "",
		"storage_engine": "",
		"meta": null
	},
	"session_provider": {
		"name": "",
		"storage_engine": "",
		"meta": null
	},
	"event_handlers": {
		"events": null
	},
	"enable_batch_request_support": false,
	"enable_ip_whitelisting": false,
	"allowed_ips": null,
	"enable_ip_blacklisting": false,
	"blacklisted_ips": null,
	"dont_set_quota_on_create": false,
	"expire_analytics_after": 0,
	"response_processors": null,
	"CORS": {
		"enable": false,
		"allowed_origins": null,
		"allowed_methods": null,
		"allowed_headers": null,
		"exposed_headers": null,
		"allow_credentials": false,
		"max_age": 0,
		"options_passthrough": false,
		"debug": false
	},
	"domain": "",
	"certificates": null,
	"do_not_track": false,
	"tags": null,
	"enable_context_vars": false,
	"config_data": null,
	"tag_headers": null,
	"global_rate_limit": {
		"rate": 0,
		"per": 0
	},
	"strip_auth_data": false,
	"enable_detailed_recording": false,
	"graphql": {
		"enabled": false,
		"execution_mode": "",
		"version": "",
		"schema": "",
		"type_field_configurations": null,
		"playground": {
			"enabled": false,
			"path": ""
		},
		"engine": {
			"field_configs": null,
			"data_sources": null
		},
		"proxy": {
			"auth_headers": null
		},
		"subgraph": {
			"sdl": ""
		},
		"supergraph": {
			"subgraphs": null,
			"merged_sdl": "",
			"global_headers": null
		}
	}
}

key.json

{
	"last_check": 0,
	"allowance": 1000,
	"rate": 1000,
	"per": 1,
	"throttle_interval": 0,
	"throttle_retry_limit": 0,
	"max_query_depth": 0,
	"date_created": "2023-01-26T17:43:28.957422224Z",
	"expires": -1,
	"quota_max": -1,
	"quota_renews": 1674759188,
	"quota_remaining": -1,
	"quota_renewal_rate": 60,
	"access_rights": {
		"2": {
			"api_name": "demoapi",
			"api_id": "2",
			"versions": [
				"Default"
			],
			"allowed_urls": [
				{
					"url": "/apidemo",
					"methods": [
						"GET"
					]
				}
			],
			"restricted_types": null,
			"limit": {
				"rate": 0,
				"per": 0,
				"throttle_interval": 0,
				"throttle_retry_limit": 0,
				"max_query_depth": 0,
				"quota_max": 0,
				"quota_renews": 0,
				"quota_remaining": 0,
				"quota_renewal_rate": 0
			},
			"field_access_rights": null,
			"allowance_scope": ""
		}
	},
	"org_id": "1",
	"oauth_client_id": "",
	"oauth_keys": null,
	"certificate": "",
	"basic_auth_data": {
		"password": "<REMOVED",
		"hash_type": "bcrypt"
	},
	"jwt_data": {
		"secret": ""
	},
	"hmac_enabled": false,
	"enable_http_signature_validation": false,
	"hmac_string": "",
	"rsa_certificate_id": "",
	"is_inactive": false,
	"apply_policy_id": "",
	"apply_policies": null,
	"data_expires": 0,
	"monitor": {
		"trigger_limits": null
	},
	"enable_detail_recording": false,
	"enable_detailed_recording": false,
	"meta_data": {},
	"tags": [],
	"alias": "",
	"last_updated": "1674759128",
	"id_extractor_deadline": 0,
	"session_lifetime": 0,
	"key_id": "<REMOVED>"
}

Error Received:

{
	"error": "Access to this resource has been disallowed"
}

@dszortyka Welcome to the community.

Seems like you have specified all auth flags to be false, including use_basic_auth

You could follow our docs about using basic auth if further stuck

Thank you for the welcome message and support, @Olu .
You’re right, I changed use_basic_auth to True in the API definition and now the endpoint is restricted.
I fixed one issue, but somehow, I’m unable to access it.

Basically, I got the user:pass, converted it to Base64 and then used it with Authorization header, like “Basic Base64Encoded”.

Now, my two suspicions are related to either the org_id field, or something related to the policies definition, I pasted our policies below in this message, just in case.

I’ll spend the next days working to sort this out, I’ll update this thread once I have any updates.

Once again, thanks for your help on this!
-Daniel

{
	"error": "User not authorised"
}

In my allowed_urls, I tried in few different ways, but in short I tried this:

"allowed_urls": [
	{
		"url": "/apidemo",
		"methods": [
			"GET"
		]
	}
],

and also like this: (with and without the trailing slash after apidemo)

"allowed_urls": [
	{
		"url": "/apidemo/(.*)",
		"methods": [
			"GET"
		]
	}
],

This is our policy file:

policies.json: |
    {
      "default": {
      "rate": 1000,
      "per": 1,
      "quota_max": 100,
      "quota_renewal_rate": 60,
      "access_rights": { }
      },
      "org_id": "1",
      "hmac_enabled": false
      }
    }

Did you create a key with based on the API or based on the policy?

You should have created a valid key associated with the API before any successful call will go through

The username should be the key ID. The password would be inputted in the key. This was my own request

POST /tyk/keys/[email protected] HTTP/1.1
Host: localhost:8080
x-tyk-authorization: <redacted>
Content-Type: application/json
Content-Length: 531

{
	"access_rights": {
		"2": {
            "allowed_urls": [
                {
                    "methods": ["GET"],
                    "url": "/apidemo"
                }
            ],
			"api_id": "2",
			"api_name": "Demo API",
			"versions": [
				"Default"
			]
		}
	},
	"allowance": 0,
    "basic_auth_data": {
		"password": "1234567",
		"hash_type": "bcrypt"
	},
	"expires": -1,
	"org_id": "1",
	"per": 60,
	"quota_max": -1,
	"quota_remaining": -1,
	"quota_renewal_rate": 60,
	"quota_renews": 1421164189,
	"rate": 1000
}

Result

{
    "key": "[email protected]",
    "status": "ok",
    "action": "added",
    "key_hash": "77ea50fb"
}

Yes, I followed those instructions before. Just in case, see the same steps you performed below.

curl -k -X POST -H "x-tyk-authorization: $TYK_API_KEY" \
 -H "Content-Type: application/json" \
 -X POST \
 -d @newuser.json http://<REDACTED/tyk/keys/[email protected]
{"key":"eyJvcmciOiIxIiwiaWQiOiJqb2huQHNtaXRoLmNvbSIsImgiOiJtdXJtdXIxMjgifQ==","status":"ok","action":"added"}
echo [email protected]:1234567 | base64   
am9obkBzbWl0aC5jb206MTIzNDU2Nwo=

If I make any changes in the base64 string, then the message changes to:

{
	"error": "Access to this resource has been disallowed"
}

Any other configuration worth having a look?

Thanks for your help!
-Daniel

Just to try outoutside Insomnia.

Using generated key for [email protected]

curl http://localhost:8080/demoapi/ --header "Authorization: eyJvcmciOiIxIiwiaWQiOiJqb2huQHNtaXRoLmNvbSIsImgiOiJtdXJtdXIxMjgifQ=="
{
    "error": "Attempted access with malformed header, header not in basic auth format"
}
echo '[email protected]:1234567' | base64

curl http://localhost:8080/demoapi/ --header "Authorization: Basic am9obkBzbWl0aC5jb206MTIzNDU2Nw=="
{
    "error": "Access to this resource has been disallowed"
}
echo [email protected]:1234567 | base64

curl http://localhost:8080/demoapi/ --header "Authorization: Basic am9obkBzbWl0aC5jb206MTIzNDU2Nwo="
{
    "error": "User not authorised"
}

You are on the right path. My guess is you are missing or forgetting a tiny bit of information.

"allowed_urls": [
                {
                    "methods": ["GET"],
                    "url": "/apidemo"
                }

You have restricted the sub paths to only allow /apidemo. That’s the reason for the error message

{
    "error": "Access to this resource has been disallowed"
}

If you call http://localhost:8080/demoapi/apidemo or add the root (/) path among the allowed urls, the issue should be resolved

"allowed_urls": [
                {
                    "url": "/apidemo",
                    "methods": ["GET" ]
                },
                {
                    "url": "(/){1}$", // using golang regex to ensure root is only matched
                    "methods": ["GET", "POST", "PUT" ]
                }
            ],

You can retrieve the key using the key id

/tyk/keys/eyJvcmciOiIxIiwiaWQiOiJqb2huQHNtaXRoLmNvbSIsImgiOiJtdXJtdXIxMjgifQ==

or using the username and org_id

/tyk/keys/[email protected]?username=true&org_id=1

Alright, it worked! :slight_smile:
Thanks a lot for your help @Olu .

[Secure your APIs by Method and Path] - Fyi, I’m pretty sure I followed this example and it didn’t work.

"allowed_urls": [
        {
            "url": "/resource/(.*)",
            "methods": ["GET", "POST"]
        }
    ]

The code below worked for me.

"allowed_urls": [
    {
        "url": "/demoapi(.*)$", # if root path is required
        "methods": ["GET" ]
    },
    {
        "url": "/demoapi/ping(.*)$",  # remove the previous line and get only __ping__
        "methods": ["GET" ]
    }
]

Thanks,
Daniel

1 Like