This guide demonstrates how to secure an API endpoint with JSON Web Tokens. Callers should not only be authenticated, but it should also be validated that the caller is in a role or has certain attributes.
To demonstrate the whole setup, a token server and an API to protect are needed. This tutorial describes how to set up both.
We will set up:
write
scope.
Why? The JWK is needed to sign and verify JWTs.
./membrane.sh generate-jwk -o ./conf/jwk.json
Add the following to your proxies.xml
:
<api port="2000" name="Token Server">
<request>
<template>
{
"sub": "user@example.com",
"aud": "order",
"scp": "read write"
}
</template>
<jwtSign>
<jwk location="jwk.json"/>
</jwtSign>
</request>
<return/>
</api>
Configure the API to require that write
is present in the scp
claim:
<api port="2001" name="Check Scope">
<jwtAuth expectedAud="order">
<jwks>
<jwk location="jwk.json"/>
</jwks>
</jwtAuth>
<if test="!exc.properties.jwt['scp'].contains('write')" language="groovy">
<static>Access Denied!</static>
<return statusCode="403"/>
</if>
<static>Access granted!</static>
<return statusCode="200"/>
</api>
./membrane.sh
Membrane will now serve:
Request a token from the token server:
curl http://localhost:2000
eyJhbGciOi...GyFA
Explanation: The token has scp: "read write"
, which meets the API’s requirement.
After retrieving the token, you can inspect it using jwt.io. Simply
paste the token there to view its payload.
You will notice that standard claims like iat
(issued at), nbf
(not before), and
exp
(expiration time) are automatically generated during the signing process.
These ensure that the token has a valid lifetime and cannot be used outside the intended time window.
Use the token to call the protected API:
curl -H "Authorization: Bearer <your-token>" http://localhost:2001
Expected response:
Access granted!
Edit the token server configuration to remove the write
scope:
<template>
{
"sub": "user@example.com",
"aud": "order",
"scp": "read"
}
</template>
Restart Membrane so that the change takes effect.
Now simply repeat Step 5 and Step 6:
write
scope).Expected result:
Access Denied!
iss
).