Open sonthonaxrk opened 5 years ago
I recently started using it. The only reason for it was that there is a couple of examples how to make it work with Okta, e.g. like this:
from flask import Flask, url_for, redirect
from flask_oidc import OpenIDConnect
app = Flask(__name__)
app.config['OIDC_CLIENT_SECRETS'] = 'client_secrets.json'
# Contents:
# Create client_id and client_secret at https://console.developers.google.com/apis/credentials
# {
# "web": {
# "client_id": "123456789012-abc123hi09123.apps.googleusercontent.com",
# "client_secret": "ab123456789ABCDEFGHIJKLM",
# "redirect_uris": ["http://localhost:5000"],
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
# "token_uri": "https://accounts.google.com/o/oauth2/token",
# "userinfo_uri": "https://www.googleapis.com/oauth2/v3/userinfo"
# }
# }
app.config['SECRET_KEY'] = 'uq4aKjUvWXTPTIyfCz7mTtcG'
app.config['OIDC_ID_TOKEN_COOKIE_SECURE'] = False
app.config['OIDC_SCOPES'] = ["openid", "profile", "email"]
app.config['OIDC_CALLBACK_ROUTE'] = '/authorization-code/callback'
oidc = OpenIDConnect(app)
@app.route('/')
@oidc.require_login
def index():
return redirect(url_for('personalized'))
@app.route('/personalized')
@oidc.require_login
def personalized():
info = oidc.user_getinfo(['email', 'openid_id'])
return 'Hello, {} ({})'.format(info.get('email'), info.get('openid_id'))
@app.route('/hello')
@oidc.require_login
def constant():
return 'Hello'
if __name__ == '__main__':
app.run(port=5000)
If there was an alternative that also provided a require_login
decorator and works with Okta, I'd be happy to switch.
This is related to #81
And #60
I am also running into some troubles... I'm trying to use this library with the Okta implicit flow (intospect call without client secret). I'll probably make a pull-request to add this but it's weird that it's not following that spec...
@MartinThoma my advice would be to roll your own code. You really just need a decorator to do a check for the authorization cookie being valid (a few lines with pyjwt), and an OIDC callback view built on top of oauthlib and pyjwt/jose.
OIDC isn't as complex as it seems.
If you want this resolved i'm maintaining a fork of this with some added extensibility. Feel free to open a PR/issue here:
This project has a large number of design issues, doesn't conform to the OIDC spec, and does some unexpected things. I'm currently refactoring this out of a project and it's surprised me on a few occasions. I appreciate it solves some issues for some people, but in the long run, doing unexpected things creates issues with interoperability and extensions.
There are also some minor security issues (forgive me if I'm wrong about any of the particulars).
exp
is ignored (after token exchange)nonce
isn't checked.oidc_id_token
cookie expiry time isn't bound to the JWT. It probably should.Given the better tools to do this like oauthlib, and pyjwt to do this job, (and probably something higher level too) perhaps the maintainers should point new projects to these tools instead.
General issues with the code:
I get this is a problem with the deprecated oauth2client. The use of JSON to configure a Python extension is odd. If you're deploying to Kubernetes you've got to base64 a group of secrets then load it up as a volume, which is simply painful. It couples all those other secrets together.
Stateful globals. I feel that having
oidc_id_token_dirty
global isn't needed. It's trigged by 'authenticate_or_redirect' (called by abefore_request
handler). Theoidc_id_token_dirty
is then then picked up by anafter_request
handler to determine if you've logged out. Just return the 401 duringauthenticate_or_redirect
, don't rely on callbacks and flags to do this.It's not following the Oauth2 spec. The way to pass tokens isn't via a cookie, it's with a
Authorization: Bearer jwt...
header. I'm not saying that cookie authentication shouldn't be an option, but it probably shouldn't have been the default.