Expired (underlying) token with JWT

Hi
I wonder how I get Tyk to “respect” the expire claim in a JWT.
(My config is available in this issue: [Solved] Key not authorized JWT - #5 by JohnPhoto , I have the same conf but sub is now a string. This works great.)

Basically I have a JWT with exp-claim which times out in 3 months. But after 1 hour after the first use with Tyk I get the following error:

Key has expired, please renew

I am trying to use the JWTs as identification for my end users rather than developer-accounts.

Am I supposed to attach something else to my JWT’s and/or send something to Tyk when I create the JWT’s?

Can you please attach your api exported json and a fresh but auth-failed jwt?
Thanks

Sure!
JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjE5In0.eyJzdWIiOiIxOSIsInRyYWNrIjoiMzcwMzQxZWMtZDUxMC00OTA2LThkODUtMzUwYWE0NjgyZWIwIiwicG9saWN5IjoiNWExZDU4ODAyMTRkZGMwNmU0YzUzYjQ3IiwiaWF0IjoxNTEyNDc5MDE4LCJleHAiOjE1MjAyNTUwMTgsImF1ZCI6InRlc3QtYXBpLmJvZmluay5jb20iLCJpc3MiOiJhdXRoLnRlc3QuYXBpLmJvZmluay5jb20ifQ.UR6iodHpf-GZfiTHUub6QaKjMs4qYFa3ZdsE3aD-0TY
{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "19"
}.{
  "sub": "19",
  "track": "370341ec-d510-4906-8d85-350aa4682eb0",
  "policy": "5a1d5880214ddc06e4c53b47",
  "iat": 1512479018,
  "exp": 1520255018,
  "aud": "test-api.bofink.com",
  "iss": "auth.test.api.bofink.com"
}

API:

{ 
    "_id" : ObjectId("5a2521ab214ddc3eaf12ffe4"), 
    "name" : "MyAPI", 
    "slug" : "myapi", 
    "api_id" : "996194c8130a4782499b94f1de4f1edc", 
    "org_id" : "5a12b183214ddc0754bb3a32", 
    "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" : "Authorization", 
        "use_certificate" : false
    }, 
    "use_basic_auth" : false, 
    "use_mutual_tls_auth" : false, 
    "client_certificates" : [

    ], 
    "upstream_certificates" : {

    }, 
    "enable_jwt" : true, 
    "use_standard_auth" : false, 
    "enable_coprocess_auth" : false, 
    "jwt_signing_method" : "hmac", 
    "jwt_source" : "SomeBase64String", 
    "jwt_identit_base_field" : "sub", 
    "jwt_client_base_field" : "", 
    "jwt_policy_field_name" : "policy", 
    "notifications" : {
        "shared_secret" : "", 
        "oauth_on_keychange_url" : ""
    }, 
    "enable_signature_checking" : false, 
    "hmac_allowed_clock_skew" : -1.0, 
    "base_identity_provided_by" : "", 
    "definition" : {
        "location" : "header", 
        "key" : "x-api-version"
    }, 
    "version_data" : {
        "not_versioned" : true, 
        "versions" : {
            "RGVmYXVsdA==" : {
                "name" : "RGVmYXVsdA==", 
                "expires" : "", 
                "paths" : {
                    "ignored" : [

                    ], 
                    "white_list" : [

                    ], 
                    "black_list" : [

                    ]
                }, 
                "use_extended_paths" : true, 
                "extended_paths" : {
                    "ignored" : [

                    ], 
                    "white_list" : [

                    ], 
                    "black_list" : [

                    ], 
                    "cache" : [

                    ], 
                    "transform" : [

                    ], 
                    "transform_response" : [

                    ], 
                    "transform_headers" : [

                    ], 
                    "transform_response_headers" : [

                    ], 
                    "hard_timeouts" : [

                    ], 
                    "circuit_breakers" : [

                    ], 
                    "url_rewrites" : [

                    ], 
                    "virtual" : [

                    ], 
                    "size_limits" : [

                    ], 
                    "method_transforms" : [

                    ], 
                    "track_endpoints" : [

                    ], 
                    "do_not_track_endpoints" : [

                    ]
                }, 
                "global_headers" : {

                }, 
                "global_headers_remove" : [

                ], 
                "global_size_limit" : NumberLong(0), 
                "override_target" : ""
            }
        }
    }, 
    "uptime_tests" : {
        "check_list" : [

        ], 
        "config" : {
            "expire_utime_after" : NumberLong(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" : NumberLong(60), 
                "endpoint_returns_list" : false
            }, 
            "recheck_wait" : NumberInt(0)
        }
    }, 
    "proxy" : {
        "preserve_host_header" : false, 
        "listen_path" : "/listen/", 
        "target_url" : "https://myTarget.com", 
        "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" : "", 
            "port_data_path" : "", 
            "target_path" : "", 
            "use_target_list" : false, 
            "cache_timeout" : NumberLong(0), 
            "endpoint_returns_list" : false
        }
    }, 
    "disable_rate_limit" : false, 
    "disable_quota" : false, 
    "custom_middleware" : {
        "pre" : [

        ], 
        "post" : [

        ], 
        "post_key_auth" : [

        ], 
        "auth_check" : {
            "name" : "", 
            "path" : "", 
            "require_session" : false
        }, 
        "response" : [

        ], 
        "driver" : "", 
        "id_extractor" : {
            "extract_from" : "", 
            "extract_with" : "", 
            "extractor_config" : {

            }
        }
    }, 
    "custom_middleware_bundle" : "", 
    "cache_options" : {
        "cache_timeout" : NumberLong(60), 
        "enable_cache" : true, 
        "cache_all_safe_requests" : false, 
        "cache_response_codes" : [

        ], 
        "enable_upstream_cache_control" : false
    }, 
    "session_lifetime" : NumberLong(0), 
    "active" : true, 
    "auth_provider" : {
        "name" : "", 
        "storage_engine" : "", 
        "meta" : {

        }
    }, 
    "session_provider" : {
        "name" : "", 
        "storage_engine" : "", 
        "meta" : {

        }
    }, 
    "event_handlers" : {
        "events" : {

        }
    }, 
    "enable_batch_request_support" : false, 
    "enable_ip_whitelisting" : false, 
    "allowed_ips" : [

    ], 
    "dont_set_quota_on_create" : false, 
    "expire_analytics_after" : NumberLong(0), 
    "response_processors" : [

    ], 
    "CORS" : {
        "enable" : false, 
        "allowed_origins" : [

        ], 
        "allowed_methods" : [

        ], 
        "allowed_headers" : [

        ], 
        "exposed_headers" : [

        ], 
        "allow_credentials" : false, 
        "max_age" : NumberInt(24), 
        "options_passthrough" : false, 
        "debug" : false
    }, 
    "domain" : "", 
    "do_not_track" : false, 
    "tags" : [

    ], 
    "enable_context_vars" : false, 
    "config_data" : {

    }, 
    "tag_headers" : [

    ], 
    "global_rate_limit" : {
        "rate" : 0.0, 
        "per" : 0.0
    }, 
    "strip_auth_data" : false, 
    "hook_references" : [

    ], 
    "is_site" : false, 
    "sort_by" : NumberInt(0)
}

Policy:

{ 
    "_id" : ObjectId("5a1d5880214ddc06e4c53b47"), 
    "org_id" : "5a12b183214ddc0754bb3a32", 
    "rate" : 15.0, 
    "per" : 1.0, 
    "quota_max" : NumberLong(-1), 
    "quota_renewal_rate" : NumberLong(3600), 
    "access_rights" : {
        "996194c8130a4782499b94f1de4f1edc" : {
            "apiname" : "MyAPI", 
            "apiid" : "996194c8130a4782499b94f1de4f1edc", 
            "versions" : [
                "Default"
            ], 
            "allowed_urls" : [

            ]
        }
    }, 
    "hmac_enabled" : false, 
    "active" : true, 
    "name" : "MyPolicy", 
    "is_inactive" : false, 
    "date_created" : ISODate("0001-01-01T00:00:00.000+0000"), 
    "tags" : [

    ], 
    "key_expires_in" : NumberLong(3600), 
    "partitions" : {
        "quota" : false, 
        "rate_limit" : false, 
        "acl" : false
    }, 
    "last_updated" : "1512383054"
}

Can you please export your api with the dashboard and send me the file? this way I have a lot of adjustments to make. thanks

Hi John,
I just saw that you have one field with a typo - missing y
“jwt_identit_base_field” : “sub”,
should be
“jwt_identity_base_field” : “sub”,

I will send you my file. But please take a look at the issue I linked in the first post. You will notice I made the same notice. But that is not the issue here. (The tyk codebase is the reason for the typo).

This Typo is fine for MongoDB use - there is a mismatch in the field names unfortunately :-/

@JohnPhoto The problem you are facing is because your policy has a trial period set. What happens with Tyk when it processes JWTs is that it requires an internal representation of the bearer in order to continue to apply rate limits and quotas across generations of JWTs, it does this by generating an internal “token” based off the subject claim in the JWT.

Because we tie JWTs to policies, when the policy is executed against the internal token, it’s expiry values are applied to the internal token too, so we actually do two expiry checks - one against the physical JWT and then later one against the bearer.

So what will have happened is that the underlying token that has been created against this JWT has a trial set, so the JWT passes validation, but the bearer does not. In order to get rid of this underlying token (this is safe, it gets recreated), you can use this little snippet here to generate the “internal” token, you can then search for this in the Key Search page of the dashboard to delete it.

In future you will be able to just search for the JWT.

Cheers,
M

This is sort of what I expected. Thank you for the snippet!

Am I safe to assume that if I (somehow) remove the trial part and start using never expiring (underlying) tokens, my JWT should work as I expect?

Yup, all you need to do is edit the policy and change the “trial period” in the dashboard UI to “Never expires”

Then the JWT will just pass through a M.D. I only valies on the JWT will be processed.

Nice, thank you all for input!
Your work here at the forum is great! @Martin @Yaara @Kos thank you so much.

2 Likes

Hi,

I encountered the same issue and found this thread, your answer helped my prob solved.

But now I realize that after I send my jwt token to api with userId and policy1, get access to my api, then I edit my jwt token (with jwt.io) to change (even remove) the policy in token payload I still able to access api.
So basically after userId is authenticated, I can use any jwt token with same Identity Source and signature to access my api, policy is not checked again.
Does it mean that Tyk does not validate access against policy if it found a session with my userId?

Thanks,

You will need to modify the policy, not the JWT. Alternatively, delete the internal token and it’s will be recreated against the new policy