Created
May 27, 2023 05:13
-
-
Save SafeEval/8cd4af27211fcf79e4fe81da66b5b1bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Pure Python3 example of using a OIDC ID token's `at_hash` claim to verify | |
an opaque OIDC access token. | |
Required for Authelia, which doesn't issue JWT access tokens. | |
If the OIDC implementation uses an /introspection endpoint to verify an opaque | |
access token, that's another HTTP call that "violates stateless purity." | |
If it's alright to add a request for that, why not one for a blocklist? | |
Three ways to verify an access token. This script focuses on the second. | |
1. Access token is a self-contained JWT. Verify independently. | |
2. Access token is an opaque string. Parse ID token's `at_hash` claim to verify. | |
3. Access token is an opaque string. Call IdP's `/userinfo` endpoint to verify. | |
https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken | |
3.1.3.6. ID Token | |
The contents of the ID Token are as described in Section 2. When using the | |
Authorization Code Flow, these additional requirements for the following | |
ID Token Claims apply: | |
at_hash | |
OPTIONAL. Access Token hash value. Its value is the base64url | |
encoding of the left-most half of the hash of the octets of the | |
ASCII representation of the access_token value, where the hash | |
algorithm used is the hash algorithm used in the alg Header | |
Parameter of the ID Token's JOSE Header. For instance, if the alg is | |
RS256, hash the access_token value with SHA-256, then take the | |
left-most 128 bits and base64url encode them. The at_hash value is a | |
case sensitive string. | |
https://auth0.com/blog/id-token-access-token-what-is-the-difference/ | |
An ID token is an artifact that proves that the user has been authenticated... | |
... so you can trust the claims about their identity. | |
OAuth 2 core specifications say nothing about the access token format. | |
https://auth0.com/docs/secure/tokens/access-tokens#opaque-access-tokens | |
If you receive an opaque Access Token, you don't need to validate it. | |
You can use it with the /userinfo endpoint, | |
""" | |
import base64 | |
import hashlib | |
at = 'authelia_at_PNQjOdymqp4e6q_AwDRXQT6BviOWvN7c7udsOKFlRa0.h638cxezuYO3GFWvzn_1fN5oJ2RZU6UZxnMQAFvAz68' | |
at_hash = 'qaL20OjGCKkjyii5Dn8wew' | |
hash = hashlib.sha256() | |
hash.update(at.encode()) | |
digest = hash.digest() | |
print("Hash digest:", digest) | |
print("Digest size:", hash.digest_size) | |
left_side = digest[:int(hash.digest_size/2)] | |
print("Left side:", left_side) | |
result = base64.urlsafe_b64encode(left_side).decode().rstrip("=") | |
print("Actual: ", result) | |
print("Expected: ", at_hash) | |
if at_hash == result: | |
print("PASS: valid access token") | |
else: | |
print("FAIL: bad access token") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment