Storing and retrieving attributes with access token

I'm using the OAuthV2 policy to store, retrieve and update custom attributes attached to the access token. Specifically, one of these attributes is a csrf_token in the form of uuid.

The GenerateAccessToken policy looks like below -

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 name="OAuthV2-GenerateAccessToken">
    <Operation>GenerateAccessToken</Operation>
    <ExpiresIn ref="flow.variable">86400000</ExpiresIn>
    <RefreshTokenExpiresIn>28800000</RefreshTokenExpiresIn>
    <SupportedGrantTypes>
        <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
    <GrantType>request.formparam.grant_type</GrantType>
    <Attributes>
        <Attribute name="csrf_token" ref="public.csrf_token" display="true">UNDEFINED</Attribute>
    </Attributes>
    <ExternalAuthorization>true</ExternalAuthorization>
    <GenerateResponse enabled="false"/>
    <DisplayName>OAuthV2-GenerateAccessToken</DisplayName>
</OAuthV2>

Every time a request is received, I use the VerifyAccessToken policy, which dumps the custom attribute into a flow variable "accesstoken.csrf_token"

I compare this value to the csrf_token received in the request, and if valid, I continue with other flows. Before returning the response, a new csrf_token is generated and I'm using the SetOAuthV2Info policy to update the value of the csrf_token attribute in the same access_token.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SetOAuthV2Info name="SetOAuthV2Info-CSRFToken" async="false">
    <AccessToken ref="ev.access_token"/>
    <Attributes>
        <Attribute name="csrf_token" ref="public.csrf_token" display="true">UNDEFINED</Attribute>
    </Attributes>
</SetOAuthV2Info>

The issue I'm facing is this. In the VerifyAccessToken policy, the value of the csrf_token dumped into the flow variable accesstoken.csrf_token is not the latest value.

Even after updating the csrf_token using the SetOAuthV2Info policy, Apigee sometimes loads the old csrf_token value into the variable hence the comparison fails.

Is this because Apigee syncs the value of these attributes asynchronously?

The documentation also states that the async attribute is deprecated.

How do I ensure that the value of the custom attribute is updated in the token DB and used by all message processors before returning a response?

Solved Solved
0 3 416
1 ACCEPTED SOLUTION

The behavior you're seeing is probably because Apigee caches the data attached to a token, and SetOAuthV2Info does not use a write-through cache.

I think the async attribute is irrelevant here.

How do I ensure that the value of the custom attribute is updated in the token DB and used by all message processors before returning a response?

The Apigee token store is not good at maintaining per-request state for web app sessions. Normally that is the job of a web app server. CSRF tokens are handled by the app server, not the API server.

If you want to have a persistent store for short-lived CSRF tokens, you might want to try the Apigee KVM. you can use the oauth token as the key. Use KVM Put with a TTL of 1s in place of SetOAuthV2Info. The KVM Put should invalidate the cache. A subsequent request replaying that token can perform a KVM Get with a TTL of 1s and retrieve the current CSRF token.

Be aware, the KVM is not intended to be a dynamic datastore for CSRF tokens. I don't know how this solution would scale. With this approach, You're writing a database record and reading a database record for every request. As the volume grows, this could stress the KVM layer, resulting in contention and limited performance.

If I were designing this system, I would not use the Apigee KVM.  I would rely on an app server for managing CSRF tokens. 

View solution in original post

3 REPLIES 3

@dchiesa1  appreciate if you can review this and help. thanks.

The behavior you're seeing is probably because Apigee caches the data attached to a token, and SetOAuthV2Info does not use a write-through cache.

I think the async attribute is irrelevant here.

How do I ensure that the value of the custom attribute is updated in the token DB and used by all message processors before returning a response?

The Apigee token store is not good at maintaining per-request state for web app sessions. Normally that is the job of a web app server. CSRF tokens are handled by the app server, not the API server.

If you want to have a persistent store for short-lived CSRF tokens, you might want to try the Apigee KVM. you can use the oauth token as the key. Use KVM Put with a TTL of 1s in place of SetOAuthV2Info. The KVM Put should invalidate the cache. A subsequent request replaying that token can perform a KVM Get with a TTL of 1s and retrieve the current CSRF token.

Be aware, the KVM is not intended to be a dynamic datastore for CSRF tokens. I don't know how this solution would scale. With this approach, You're writing a database record and reading a database record for every request. As the volume grows, this could stress the KVM layer, resulting in contention and limited performance.

If I were designing this system, I would not use the Apigee KVM.  I would rely on an app server for managing CSRF tokens. 

A Cloud Function implementation over Cloud Memorystore I imagine would suit better than using the KVM