Skip to main content

License Support PyPI Code Style

Okta JWT Verifier for Python

This library helps you verify tokens that have been issued by Okta. To learn more about verification cases and Okta's tokens please read Working With OAuth 2.0 Tokens

Requires Python version 3.6.0 or higher.

Release status

This library uses semantic versioning and follows Okta's Library Version Policy.

Version Status
0.x ✔️ Beta Release

The latest release can always be found on the releases page.

Need help?

If you run into problems using the SDK, you can

Getting started

To install Okta JWT Verifier Python:

pip install okta-jwt-verifier

This library was built to keep configuration to a minimum. To get it running at its most basic form, all you need to provide is the the following information:

  • Issuer - This is the URL of the authorization server that will perform authentication. All Developer Accounts have a "default" authorization server. The issuer is a combination of your Org URL (found in the upper right of the console home page) and /oauth2/default. For example, https://dev-1234.oktapreview.com/oauth2/default.
  • Client ID - These can be found on the "General" tab of the Web application that you created earlier in the Okta Developer Console.
  • Audience - By default api://default, can be found on Authorization Servers tab.

Following example will raise an JWTValidationException if Access Token is invalid:

import asyncio

from okta_jwt_verifier import BaseJWTVerifier


async def main():
    jwt_verifier = BaseJWTVerifier(issuer='{ISSUER}', audience='api://default')
    await jwt_verifier.verify_access_token('{JWT}')
    print('Token validated successfully.')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Usage guide

These examples will help you understand how to use this library.

Verify ID Token:

import asyncio

from okta_jwt_verifier import BaseJWTVerifier


async def main():
    jwt_verifier = BaseJWTVerifier(issuer='{ISSUER}', client_id='{CLIENT_ID}', audience='api://default')
    await jwt_verifier.verify_id_token('{JWT}', nonce='{NONCE}')
    print('Token validated successfully.')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Note: parameter nonce is optional and required only if token was generated with nonce.

Another option - use class dedicated to ID tokens verification:

import asyncio

from okta_jwt_verifier import IDTokenVerifier


async def main():
    jwt_verifier = IDTokenVerifier(issuer='{ISSUER}', client_id='{CLIENT_ID}', audience='api://default')
    await jwt_verifier.verify('{JWT}', nonce='{NONCE}')
    print('Token validated successfully.')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Verify Access Token

import asyncio

from okta_jwt_verifier import AccessTokenVerifier


async def main():
    jwt_verifier = AccessTokenVerifier(issuer='{ISSUER}', audience='api://default')
    await jwt_verifier.verify('{JWT}')
    print('Token validated successfully.')


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

It is possible to verify signature if JWK is provided (no async requests):

from okta_jwt_verifier import BaseJWTVerifier


def main():
    jwt_verifier = BaseJWTVerifier('{ISSUER}', '{CLIENT_ID}', 'api://default')
    jwt_verifier.verify_signature('{JWT}', {JWK})


main()

The following example shows how to receive JWK using async http request:

import asyncio

from okta_jwt_verifier import BaseJWTVerifier


async def main():
    jwt_verifier = BaseJWTVerifier('{ISSUER}', '{CLIENT_ID}', 'api://default')
    headers, claims, signing_input, signature = jwt_verifier.parse_token({JWT})
    okta_jwk = await self.get_jwk(headers['kid'])

    # Then it can be used to verify_signature as in example above.
    jwt_verifier.verify_signature('{JWT}', okta_jwk)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

It is possible to verify only given list of claims (no async requests):

from okta_jwt_verifier import BaseJWTVerifier


def main():
    claims_to_verify = ['aud', 'iss']
    jwt_verifier = BaseJWTVerifier('{ISSUER}', '{CLIENT_ID}', 'api://default')
    headers, claims, signing_input, signature = jwt_verifier.parse_token({JWT})
    jwt_verifier.verify_claims(claims, claims_to_verify)


main()

or token expiration only (no async requests):

from okta_jwt_verifier import BaseJWTVerifier


def main():
    jwt_verifier = BaseJWTVerifier('{ISSUER}', '{CLIENT_ID}', 'api://default')
    jwt_verifier.verify_expiration('{JWT}', leeway=0)


main()

v 0.2.0 allows to work via proxy:

# BaseJWTVerifier will be deprecated soon
jwt_verifier = BaseJWTVerifier(issuer='{ISSUER}', proxy='{PROXY}')

# The same for AccessTokenVerifier
jwt_verifier = AccessTokenVerifier(issuer='{ISSUER}', proxy='{PROXY}')

# or IDTokenVerifier
jwt_verifier = IDTokenVerifier(issuer='{ISSUER}', proxy='{PROXY}')

Exceptions

If token is invalid (malformed, expired, etc.), verifier will raise an exception JWTValidationException:

import asyncio

from okta_jwt_verifier import BaseJWTVerifier


async def main():
    jwt_verifier = BaseJWTVerifier('{ISSUER}', '{CLIENT_ID}', 'api://default')
    await jwt_verifier.verify_access_token(access_token)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Output (part of traceback removed for simplicity):

Traceback (most recent call last):
...
okta_jwt_verifier.exceptions.JWTValidationException: Signature has expired.

If configuration provided is invalid, verifier will raise an exception JWTInvalidConfigException:

import asyncio

from okta_jwt_verifier import BaseJWTVerifier


async def main():
    jwt_verifier = BaseJWTVerifier('malformed_issuer.com', '{CLIENT_ID}', 'api://default')
    await jwt_verifier.verify_access_token(access_token)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Output (part of traceback removed for simplicity):

Traceback (most recent call last):
...
okta_jwt_verifier.exceptions.JWTInvalidConfigException: Your Okta URL must start with 'https'.

If JWK is invalid, verifier will raise an exception JWKException:

import asyncio

from okta_jwt_verifier import BaseJWTVerifier


async def main():
    jwt_verifier = BaseJWTVerifier('{ISSUER}', '{CLIENT_ID}', 'api://default')
    await jwt_verifier.verify_access_token(access_token)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Output (part of traceback removed for simplicity):

Traceback (most recent call last):
...
okta_jwt_verifier.exceptions.JWKException: No matching JWK.

Contributing

We're happy to accept contributions and PRs! Please see the Contribution Guide to understand how to structure a contribution.

Metadata

Release files for okta-jwt-verifier 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for okta-jwt-verifier 0.5.0
File Size Uploaded
okta_jwt_verifier-0.5.0.tar.gz 15.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for okta-jwt-verifier 0.5.0
File Interpreter ABI Platform
okta_jwt_verifier-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.9 kB

Release files / okta_jwt_verifier-0.5.0.tar.gz

Download URL okta_jwt_verifier-0.5.0.tar.gz
Size 15.4 kB
Tags Source
SHA-256 checksum
How to use checksums
4fe6e4f4ffff6c03b6b63a7709b879bdaf57025ae1dcc06ea2f32dd4a07963df
BLAKE2b-256 checksum
How to use checksums
d0b63e85f92cbb851c2bd57b67efcb8485c1f88f595dba1f072d688a3802dee1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.10

Release files / okta_jwt_verifier-0.5.0-py3-none-any.whl

Download URL okta_jwt_verifier-0.5.0-py3-none-any.whl
Size 16.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
af41e947759ffeb65149aeafb81c065c1eeb4eeda5880f0b9d755a96f1db1cee
BLAKE2b-256 checksum
How to use checksums
08f2add78bad59c902a0c97ebdc8bf193b8364fdac3ea87148948018f3835095
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.10

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

3 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page