question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

parse_id_token() returns None

See original GitHub issue

Describe the bug

The method parse_id_token returns None, even though the client is properly configured and the response of the IDP is valid.

To Reproduce

Code:

# pylint: skip-file
import os
import json

import django
from authlib.integrations.django_client import OAuth
from django.urls import path
from django.urls import reverse
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.management import call_command
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse
from django.shortcuts import redirect


settings.configure(
    AUTHLIB_OAUTH_CLIENTS={
        'dcsp': {
            'client_id': 'confidential',
            'client_secret': "secret",
            'client_kwargs': {
                'scope': 'openid profile email',
                'response_type': 'code id_token'
            },
        }
    },
	DATABASES = {
	  'default': {
		'ENGINE': 'django.db.backends.sqlite3',
		'NAME': 'var/django-client-authlib.db',
	  }
	},
    DEBUG=True,
    INSTALLED_APPS=[
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
    ],
    LOGIN_URL='/login',
    MIDDLEWARE=[
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
    ],
    ROOT_URLCONF = '__main__',
    SECRET_KEY='changeme',
    WSGI_APPLICATION = '__main__.application'
)


def login(request):
    redirect_uri = request.build_absolute_uri('/authorize')
    return oauth.dcsp.authorize_redirect(request, redirect_uri)



def home(request):
    user = request.session.get('user')
    if not user:
        return redirect('/login')
    user = json.dumps(user, indent=2, sort_keys=True)
    return HttpResponse(user, content_type="application/json")


def auth(request):
    token = oauth.dcsp.authorize_access_token(request)
    user = oauth.dcsp.parse_id_token(request, token)
    assert user, json.dumps(token, indent=2, sort_keys=True)
    request.session['user'] = user
    return redirect('/')


def logout(request):
    request.session.pop('user', None)
    return redirect('/')


application = get_wsgi_application()

urlpatterns = [
    path('', home),
    path('login', login),
    path('logout', logout),
    path('authorize', auth, name='auth'),
]


if __name__ == '__main__':
    os.environ['CURL_CA_BUNDLE'] = '' # Hack to disable SSL
    django.setup()
    oauth = OAuth()
    oauth.register(
        name='dcsp',
        server_metadata_url="https://localhost:8000/.well-known/openid-configuration",
    )
    call_command('migrate')
    call_command('runserver',  '127.0.0.1:5000')

JSON serialized output of authorize_access_token():

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJraWQiOiJmZWI2NDc0N2UxYzQ3NWVjZjE4ZjM5ODc4YzUxOTViMCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI3NzM3YTVlYi01N2VkLTRlOWItOTUyOC0xYWZlOGNjZWQyY2UiLCJleHAiOjE2MzU5NTgwMjMsImlhdCI6MTYzNTk1NzQyMywibmJmIjoxNjM1OTU3NDIzLCJqdGkiOiJjYzA0OTVkMDlmZGRiNjIxODZjM2ZhMDJmNzFjYmRlYSIsImNsaWVudF9pZCI6ImNvbmZpZGVudGlhbCIsInJsbSI6ImN3aSIsInNjb3BlIjpbImVtYWlsIiwib3BlbmlkIiwicHJvZmlsZSJdfQ.FaUlVcJQepN6l5ok_07V3eu_0rwAqjsY-Bfu8U-70je-4PrZNmcqyzlf3F00TYjOs90sfOZDzC1TYdNc353R0P8vziXDZt0Sp4qjWk2WOl5VFjX7_EL0WJQ7UhrnvcuVRYRIaYpr18CS15Hy4wVblM7F1j9kWIiNOB8NtcpxQGHwYpPX8DsSCR7si50-yRTacoWQaYXx_1lf0AhAkD3JsMu0bKAtzmpsBRaurUlUpVbqjCeFZQ6-JythZ0XO5qSwHhz0R-aZBy6U3fVQy8TDoYz_NubcO3pKEUwsqWoK05zfe7c9NFXfWEpxjMJDZwWCOPKK9NU7fal6mpIlhRHulNJBSfHzAk97zXIE9HQMSbUCm4LeJYJoheuV-cSznfb_mgOgVXoOlUs1H4uptvHa_GKqr0c0YhHqEHSFXqNrz210JI6BEbv0M8XmZAct542hmH0IFMjEOnPw8ZJNBFe0IY3g1cSn4djF0sKnUut8pcF6ch25HpybNnWpF5_JL0hnGugGZrQlHzOdTlZaAggOK3fn6qLVTbrTWXt4g2zT8YX3SXkmAnJLP52JfKw0PAr98sDdNpDLbn_m3BH7Ilkz6T8fl8dN6qxxE8eTXGXF2E5WHqBP4R0TwGNlIAeiC84lCUhtABExn-vCBks_Z23Vskt2QV1lcxK6e9Bsq0JZkXc",
  "expires_at": 1635958023,
  "expires_in": 600,
  "id_token": "eyJ0eXAiOiJKV1QiLCJraWQiOiJmZWI2NDc0N2UxYzQ3NWVjZjE4ZjM5ODc4YzUxOTViMCIsImFsZyI6IlJTMjU2In0.eyJqdGkiOiJjNTZlYzRhN2JhYWUxZjFlMmZjMGRiMzllN2M1NjcwZSIsImlhdCI6MTYzNTk1NzQyMywiZXhwIjoxNjM1OTkzNDIzLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo4MDAwIiwicmxtIjoiY3dpIiwiYXVkIjpbImh0dHBzOi8vbG9jYWxob3N0OjgwMDAiXSwic3ViIjoiNzczN2E1ZWItNTdlZC00ZTliLTk1MjgtMWFmZThjY2VkMmNlIiwiYXpwIjoiY29uZmlkZW50aWFsIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImVtYWlsIjoiY29jaGlzZS5ydWh1bGVzc2luQGN3aS5ubCIsImF1dGhfdGltZSI6MTYzNTk1MTMwMSwibmFtZSI6bnVsbCwibmlja25hbWUiOm51bGwsImdpdmVuX25hbWUiOiJDb2NoaXNlIiwiZmFtaWx5X25hbWUiOiJSdWh1bGVzc2luIiwibWlkZGxlX25hbWUiOm51bGwsIm5vbmNlIjoibmJqcVZtMmlxWHFldEk1dGdLVGQifQ.UoTJMT5BcqXwZx7hAGdDaLaE-6X6UQilkaiw-MMdxlObXnd7GozxsdS30ice7xbsuxhhKo_g5l5hnv5Qqd2OZHhZujGY3rw6Ox575d6f4i6oimYI5tLmztM1Vg_4CUO-Z8yjidy0dEGLodSCSz1EKzKtsDOFkGtaOU58iZbkVFIqSQH6bki309NKE7Mp64ow7Ww8IrM7Dfc1z_Y6Oc6LTo0SAASS7WSE0TR-7isVFjq32ZatQoPrRiEAfgSG3TCI_FhnRjYR3qXps6tIa78wPUmF16euWPQ_Ik_o6g7PiMqjPMoE58_iSLL9y_Y3dfGiNIYkRvgJuGf6PqpgHN8Sd0wIp_aLHxoiSN5haKILQ4MPC7NPkU6C-rrBfnK1fLLM5ofcGrP25y3pFmKvDMdCGXp4PFcu5TcefAjK4gnmmslRJQEWZbkGg7C67U2yFC-oLp-WCFliQ6R9R3zJAmQk_nW8jIB7xQs-zBvgjlk-J866BJ5KuwsXAK0UUoIaRMN0BIlAdARGjyhoxR0HntNCgBMFpWZ2e9M5zukaR17dfyODqKuX4O0PnhiWaH9Tw27GBdCUsHEKxi7pcgmEi9C_BePSPAnfupV68XweO27Ns8Nr0GPLVG113LdRrrsuhnbH392SvP_3tm1LApawSHFCtnb51SiRnlqXTWvAZBo-CeM",
  "refresh_token": "ce8f110c95c685d7d4744797aab8c2cd443b8a8d37371e2cdc07617f842073c2",
  "token_type": "Bearer",
  "userinfo": {
    "aud": [
      "https://localhost:8000"
    ],
    "auth_time": 1635951301,
    "azp": "confidential",
    "email": "<redacted>",
    "email_verified": true,
    "exp": 1635993423,
    "family_name": "Ruhulessin",
    "given_name": "Cochise",
    "iat": 1635957423,
    "iss": "https://localhost:8000",
    "jti": "c56ec4a7baae1f1e2fc0db39e7c5670e",
    "middle_name": null,
    "name": null,
    "nickname": null,
    "nonce": "nbjqVm2iqXqetI5tgKTd",
    "rlm": "cwi",
    "sub": "7737a5eb-57ed-4e9b-9528-1afe8cced2ce"
  }
}

Expected behavior

The return value of parse_id_token is not None

Environment:

  • OS: Mac OS
  • Python Version: 3.9
  • Authlib Version: 1.0.0b2

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
rusnydercommented, Apr 13, 2022

Sorry in advance for commenting on a closed ticket, but I just stumbled across this when upgrading to Authlib 1.x and found that the API change for parse_id_token wasn’t mentioned in either the Changelog (https://docs.authlib.org/en/latest/changelog.html) or in the “1.x breaking changes” guide (https://gist.github.com/lepture/506bfc29b827fae87981fc58eff2393e).

I was wondering if it made sense to add a note about this change to either/both locations for those also upgrading in the future.

1reaction
lepturecommented, Nov 16, 2021

Sorry about the documentation. I’ve fixed the documentation.

You don’t need to call parse_id_token yourself, userinfo is already in token now:

token = oauth.dcsp.authorize_access_token(request)
userinfo = token['userinfo']
Read more comments on GitHub >

github_iconTop Results From Across the Web

google oauth - GoogleTokenResponse.getIdToken() returns null
getIdToken() is returning null, so I assume that's what's causing the NPE when I call parseIdToken(). What would cause getIdToken() to return ......
Read more >
GoogleTokenResponse (google-api-client 1.32.2) - javadoc.io
Sets the ID token. Overriding is only supported for the purpose of calling the super implementation and changing the return type, but nothing...
Read more >
Class IdTokenResponse (1.34.1) | Java client library
public IdToken parseIdToken(). Parses using JsonWebSignature#parse(JsonFactory, String) based on the JSON factory and ID token. Returns ...
Read more >
google-api-java-client/GoogleTokenResponse.java at main
return (GoogleTokenResponse) super. ... changing the return type, but nothing else. ... public GoogleIdToken parseIdToken() throws IOException {. return ...
Read more >
com.google.api.client.googleapis.auth.oauth2.GoogleIdToken ...
try { return GoogleIdToken.parse(jsonFactory, token); ... idToken : null; } ... @Beta public GoogleIdToken parseIdToken() throws IOException { return ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found