Skip to content

Commit c561bc2

Browse files
jwt-claims as arguments example (#49)
* jwt-claims as arguments example * cleanup * cleanup * cleanup * cleanup * Update README.md simple typo fix --------- Co-authored-by: Carlos Eberhardt <[email protected]>
1 parent 14fab79 commit c561bc2

File tree

6 files changed

+144
-0
lines changed

6 files changed

+144
-0
lines changed

protection/jwt-claims/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Pulling field arguments from JWT claims
2+
3+
This snippet shows how JWT claims can be used for field arguments.
4+
5+
This examples demonstrates a number of StepZen capabilities:
6+
7+
- Authorization using JWT
8+
- Field access rules
9+
- Field visibility patterns
10+
- `@value` directive with access to JWT claims
11+
- https://www.ibm.com/docs/en/api-connect/ace/saas?topic=directives-directive-value
12+
- Reshaping
13+
14+
## Restricting access through JWT claims.
15+
16+
This example shows how a JWT claim may be used as a field argument, in this case the JWT subject claim
17+
is used as a customer's identifier. Thus the customer can only view their own information even though
18+
the backend database includes all customers.
19+
20+
The field `Query.customer` provides an identifier lookup to all customers. This field is restricted
21+
from being executed by field visibility and access rules.
22+
23+
Instead a field `Query.me` is exposed with no field arguments that invokes `Query.customer`
24+
with the customer identifier pulled from the `sub` claim in the request's JWT.
25+
26+
This is implemented using `@sequence` with the first step an intermediate field (`Query._myid`) that is annotated with `@value` using ECMAScript.
27+
This script has access to field arguments of its annotated field (in this case none) and JWT claims through `$jwt`.
28+
Thus it returns the `sub` claim which is then automatically mapped as a scalar value to the sole argument of
29+
the next step in the sequence (`Query.customer(id:)`).
30+
31+
An alternate version of `Query._myid` exists `Query._my_id_jsonata` showing that scripts can be implemented in JSONata.
32+
The default language is ECMAScript.
33+
34+
Note these concepts could be combined with field access through ABAC rules (see `protection/simpleABACSample`)
35+
so that `Query.customer` could be exposed, but only customer service reps could call it
36+
with any customer identifier.
37+
38+
## Try it out!
39+
40+
Deploy the schema from `protection/jwt-claims` relative to the repository's root directory:
41+
42+
```
43+
stepzen deploy
44+
```
45+
46+
Run the [sample operations](operations.graphql):
47+
48+
JWT with `sub: 5`.
49+
50+
JWT: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1In0.LE_mbGsS2FbxF41r4wOYKhWdBoYhnIk0-6d6U7ibF-A
51+
52+
Secret Key: development-only
53+
54+
```
55+
stepzen request -f operations.graphql --operation-name=Customer --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1In0.LE_mbGsS2FbxF41r4wOYKhWdBoYhnIk0-6d6U7ibF-A"
56+
```
57+
58+
JWT with `sub: 9`.
59+
60+
JWT: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1In0.LE_mbGsS2FbxF41r4wOYKhWdBoYhnIk0-6d6U7ibF-A
61+
62+
Secret Key: development-only
63+
64+
```
65+
stepzen request -f operations.graphql --operation-name=Customer --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5In0.liX79YjQ1EIqdVSLqvKoVJxoj63OkBANwZLsZcdLzDM"
66+
```

protection/jwt-claims/api.graphql

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
type Customer {
2+
id: ID!
3+
name: String
4+
email: String
5+
}
6+
7+
type Query {
8+
"""
9+
Fetch customer by identifier.
10+
"""
11+
customer(id: ID!): Customer
12+
@dbquery(
13+
type: "postgresql"
14+
table: "customer"
15+
schema: "public"
16+
configuration: "postgresql_config"
17+
)
18+
19+
"""
20+
Fetch my customer information.
21+
Customer identifier is pulled from the JWT subject claim.
22+
"""
23+
me: Customer @sequence(steps: [{ query: "_myid" }, { query: "customer" }])
24+
25+
"""
26+
Extract the customer's identifier from a claim in a JWT.
27+
"""
28+
_myid: ID! @value(script: { src: "$jwt.sub" })
29+
30+
"""
31+
Extract the customer's identifier from a claim in a JWT using JSONATA.
32+
"""
33+
_myid_jsonata: ID! @value(script: { src: "`$jwt`.sub", language: JSONATA })
34+
}

protection/jwt-claims/config.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
deployment:
2+
identity:
3+
keys:
4+
- algorithm: HS256
5+
key: development-only
6+
access:
7+
policies:
8+
- type: Query
9+
policyDefault:
10+
condition: false
11+
rules:
12+
- name: "jwt-control"
13+
fields: [me]
14+
condition: "?$jwt"
15+
- name: "introspection"
16+
fields: [__schema, __type]
17+
condition: true
18+
configurationset:
19+
- configuration:
20+
name: postgresql_config
21+
uri: postgresql://postgresql.introspection.stepzen.net/introspection?user=testUserIntrospection&password=HurricaneStartingSample1934
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
schema
2+
@sdl(
3+
files: ["api.graphql"]
4+
# visibilty controls how fields included through files in this directive
5+
# are visible outside the scope of this directive to GraphQL introspection
6+
# and field references through @materializer etc.
7+
#
8+
# types and fields are regular expressions that match type and field names.
9+
# Like field access rules if aat least one visibility pattern is present then by default
10+
# root operation type (Query, Mutation, Subscription) fields are not exposed.
11+
visibility: [{ expose: true, types: "Query", fields: "me" }]
12+
) {
13+
query: Query
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
query Customer {
2+
me {
3+
id
4+
name
5+
}
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"endpoint": "api/miscellaneous"
3+
}

0 commit comments

Comments
 (0)