API Connect

API Connect

Join this online group to communicate across IBM product users and experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.

 View Only

Caching techniques for oauth token endpoints

  • 1.  Caching techniques for oauth token endpoints

    Posted 10 hours ago
    Edited by Brendon Stephens 8 hours ago
    Hi All
     
    I have a requirement to cache oauth token responses. I am managing the oauth token call using urlopen within Gatewayscript. After playing around for a bit, I was able to get caching working by defining a fixed dynamic caching policy, however, whenever I add an Authorization header to the request, Datapower will not honour the fixed cache policy.
     
    I am curious if there is a way around this, or if there are alternative and better solutions to caching the token. Unfortunately, the backend oauth provider will not support client_secret based authentication at this stage. In our current implementation we have achieved caching by routing through an intermediate sub-service. So we cache the sub-service (without Authorization) rather than the actual backend /token call.
     
    Below is a snippet of the code I was playing around with. As mentioned, the caching works until I add the Authorization header, so I think it is by design that the cache is not honoured. Note this is intended to be an APIC service, so I found that using a dynamic policy was the only option within Gatewayscript. I believe this is how the Invoke function operates in the background too.
     
    One alternative solution I was considering was using the distributed-metadata module and managing the cache manually myself. I am not sure if this is an antipattern or not, so seeking advice from the community.
     
    Options considered (using APIC):
    • Cache using Invoke (doesn't work with Auth header)
    • Cache in gws using dynamic cache policy (doesn't work with Auth header)
    • Defining custom gateway extension (would rather avoid, and I imagine same issue as above)
    • Cache by using intermediate service that maps Auth header.

    My question is

    1. What is the most appropriate way to manage caching in APIC using Gatewayscript?
    2. Is there any way to force the cache even when there is an Authorization header present.
    Thanks.
     
     
    20250613T042616.160Z [0x80e008c5][network][debug] apigw(): tid(15595569)[10.245.104.199] gtid(196c5565684ba86800e2aa23): Document cache: cannot cache due to the request has the 'Authorization' header: URL http://example.com:1236/sap/bc/sec/oauth2/token?sap_client=432
     
    const sm = require('service-metadata')
    const urlopen = require('urlopen');
    const { URLSearchParams } = require('url');
    
    
    const ttl = 900 // 15 minutes
    
    
    const host = 'https://example.com'
    const path = '/oauth2/token'
    const endpoint = `${host}${path}`
    
    
    const clientId = 'client'
    const clientSecret = 'secret'
    const authorization = Buffer.from(clientId + ":" + clientSecret).toString('base64');
    
    
    const cachingPolicy = `
    <dcp:caching-policies xmlns:dcp="http://www.datapower.com/schemas/caching">
        <dcp:caching-policy url-match="${host}${path}" priority="200">
            <dcp:fixed ttl="${ttl}" 
                cache-post-put-response="true" 
                cache-backend-response="true" 
                http-cache-validation="false" 
                return-expired-document="false" 
                restful-invalidation="false" 
            />
        </dcp:caching-policy>
    </dcp:caching-policies>`
    
    
    sm.setVar('var://service/cache/dynamic-policies', cachingPolicy)
    
    
    const data = new URLSearchParams({
        grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer',
        client_id: clientId,
        client_secret: clientSecret,
        assertion: 'blah',
        scope: 'scope'
    }).toString()
    
    
    try {
        urlopen.open({
            target: endpoint,
            method: 'post',
            data,
            headers: {
                'Accept': 'application/json',
                //'Authorization': `Basic ${authorization}`, 
                'x-dp-cache-key': 'test' // ie. always return cache.
            },
            contentType: 'application/x-www-form-urlencoded',
            timeout: 60
        }, (error, response) => {
        
            if (error) {
                return context.message.body.write({
                    message: 'urlopen error',
                    error,
                    context
                });
            }
        
            response.readAsBuffer((error, body) => {
                if (error) {
                    return context.message.body.write({
                        message: 'read token error',
                        error,
                        context
                    });
                }
                context.message.body.write(body);
            })
        })
    } finally {
        sm.setVar('var://service/cache/dynamic-policies', 
            `<dcp:caching-policies xmlns:dcp="http://www.datapower.com/schemas/caching"/>`)
    }
     
     
     
     
     
     



    ------------------------------
    Brendon Stephens
    ------------------------------