Any examples of setting up well-known url using authlib?

Viewed 355

I am evaluating Authlib for setting up OpenID connect and Oauth2.0 authorization server. It worked well for me so far. I was trying to see if well-known url could be published easily, so that I can get applications written in SpringBoot work with the JWTs issued by the Authlib server.

https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2resourceserver

I couldn't find much documentation or samples on how to publish the well-known url endpoint. Any guidance in this regard, would be highly appreciated.

2 Answers

I could not find an answer for this question as well, so a copy the Google well-known response. Hope it helps.

def openid_configuration():
    return dict(
        issuer=current_app.config['BACKEND_URL'],
        authorization_endpoint=f"{current_app.config['FRONTEND_URL']}/authorize",
        device_authorization_endpoint=None,
        token_endpoint=f"{current_app.config['BACKEND_URL']}/api/token",
        userinfo_endpoint=None,
        revocation_endpoint=None,
        jwks_uri=f"{current_app.config['BACKEND_URL']}/api/public-key",
        response_types_supported=["code"],
        subject_types_supported=[],
        id_token_signing_alg_values_supported=["RS256"],
        scopes_supported=["openid", "email", "actions", "meta"],
        token_endpoint_auth_methods_supported=["client_secret_post"],
        claims_supported=["email", "iat", "iss", "name", "sub"],
        code_challenge_methods_supported=[],
        grant_types_supported=["authorization_code"]
    )

I was able to extend the oidc flask example with this handler

@bp.route("/.well-known/openid-configuration")
def well_known_openid_configuration():
    def external_url(function_name):
        return url_for(function_name, _external=True)
    
    return jsonify({
        "authorization_endpoint": external_url('.authorize_endpoint'),
        "token_endpoint": external_url('.token_endpoint'),
        "userinfo_endpoint": external_url('.userinfo_endpoint'),
        "jwks_uri": external_url('.jwks_endpoint'),
        # Do I even need this one?
        # IMO the OIDC server doesn't have a concept of a user being still logged in? --mh
        # "end_session_endpoint": "http://oidc:4000/openid/end-session",
        "id_token_signing_alg_values_supported": [
            "HS256",
            "RS256"
        ],
        "issuer": JWT_CONFIG['iss'],
        "response_types_supported": [
            "code",
            # TODO check what it takes to support these too
            # "id_token",
            # "id_token token",
            # "code token",
            # "code id_token",
            # "code id_token token"
        ],
        "subject_types_supported": [
            "public"
        ],
        "token_endpoint_auth_methods_supported": [
            # TODO is supporting both a good idea? --mh
            "client_secret_post",
            "client_secret_basic"
        ],
    })

Turns out implementing the jwks_uri endpoint wasn't so hard, it works roughly like this:


def load_public_keys():
    public_key_path = Path("etc") / "public.pem"
    public_key = JsonWebKey.import_key(public_key_path.read_bytes())
    public_key["use"] = "sig"
    public_key["alg"] = "RS256"    
    return KeySet([public_key])

@bp.route("/oauth/jwks")
def jwks_endpoint():
    return jsonify(load_public_keys().as_dict())

To get authlib to use the private key and set the key id (kid), this was required in the JWT_CONFIG

JWT_CONFIG = {
    "key": "secret-key",
    "alg": "RS256",
    "iss": "https://sntl-publishing.com",
    "exp": 3600,
}
private_key_path = Path('etc') / 'private.pem'
private_key = JsonWebKey.import_key(private_key_path.read_text())
JWT_CONFIG['key'] = KeySet([private_key]).as_dict()

It seems to be fixed in the master version in the repo, but in the currently released version you need the as_dict() call on the KeySet - else the kid is not part of the generated id token nd the client will not be able to verify it with the information from the jwks_uri endpoint.

Related