Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

I Don't Care About Security (And Neither Should You)

114 views

Published on

Remember when setting up a login page was easy? It seems like nowadays it can take weeks to start a project -- creating a signup form, a login form, a password recovery screen, and all the validation in between. And you haven't even started on security considerations yet. During this presentation, the attendees will be introduced to OpenID Connect and OAuth. They will also learn how to leverage these technologies to create more secure applications. Most importantly, they will learn how to delegate authorization and authentication so they can focus on their real work and forget about all that security stuff.

Published in: Internet
  • Did you know that once you lose your Ex, there is still a good chance you can get them back? Learn how ▲▲▲ http://ishbv.com/exback123/pdf
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Be the first to like this

I Don't Care About Security (And Neither Should You)

  1. 1. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU)
  2. 2. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU)
  3. 3. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) ABOUT ME ▸ Passionate about tech ▸ Technical Evangelist at Auth0, Author at Udemy, Egghead @joel__lord
  4. 4. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  5. 5. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  6. 6. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  7. 7. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  8. 8. INTRODUCING OAUTH!
  9. 9. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  10. 10. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  11. 11. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  12. 12. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  13. 13. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  14. 14. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OAUTH FLOWS
  15. 15. BUT WHY ?
  16. 16. DELEGATION!
  17. 17. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TRADITIONAL APPLICATIONS ▸ Browser requests a login page
  18. 18. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TRADITIONAL APPLICATIONS ▸ Browser requests a login page
  19. 19. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TRADITIONAL APPLICATIONS ▸ Browser requests a login page
  20. 20. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TRADITIONAL APPLICATIONS ▸ Browser requests a login page ▸ Server validates on the database
  21. 21. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TRADITIONAL APPLICATIONS ▸ Browser requests a login page ▸ Server validates on the database 👍
  22. 22. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TRADITIONAL APPLICATIONS ▸ Browser requests a login page ▸ Server validates on the database ▸ It creates a session and sends back a cookie identifier 👍
  23. 23. "
  24. 24. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) WHAT’S WRONG WITH TRADITIONAL AUTHENTICATION? ▸ Multiple platforms connecting to your application
  25. 25. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) WHAT’S WRONG WITH TRADITIONAL AUTHENTICATION? ▸ Multiple platforms connecting to your application ▸ Tightly coupled
  26. 26. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) WHAT’S WRONG WITH TRADITIONAL AUTHENTICATION? ▸ Multiple platforms connecting to your application ▸ Tightly coupled ▸ Sharing credentials to connect to a third party API
  27. 27. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) WHAT’S WRONG WITH TRADITIONAL AUTHENTICATION? ▸ Multiple platforms connecting to your application ▸ Tightly coupled ▸ Sharing credentials to connect to a third party API ▸ Users have a gazillions accounts already, which leads to password reuse and lower conversion rates
  28. 28. OAUTH GRANTS I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU)
  29. 29. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  30. 30. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  31. 31. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  32. 32. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE 👍
  33. 33. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE 👍
  34. 34. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  35. 35. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  36. 36. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  37. 37. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  38. 38. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  39. 39. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE ⛔
  40. 40. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  41. 41. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) AUTHORIZATION CODE
  42. 42. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  43. 43. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  44. 44. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  45. 45. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  46. 46. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT 👍
  47. 47. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  48. 48. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  49. 49. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT
  50. 50. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) IMPLICIT GRANT 👍
  51. 51. TOKENS 101 I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU)
  52. 52. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TOKENS ▸ Access Tokens ▸ Gives you access to a resource ▸ Controls access to your API ▸ Short Lived ▸ Refresh Tokens ▸ Enable you to get a new access token ▸ Longed lived ▸ Can be revoked
  53. 53. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TOKENS ▸ Refresh Tokens ▸ Enable you to get a new access token ▸ Longed lived ▸ Can be revoked
  54. 54. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TOKENS ▸ Refresh Tokens ▸ Enable you to get a new access token ▸ Longed lived ▸ Can be revoked
  55. 55. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TOKENS ▸ WS Federated ▸ SAML ▸ Custom stuff ▸ …
  56. 56. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) TOKENS ▸ WS Federated ▸ SAML ▸ Custom stuff ▸ JWT
  57. 57. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) eyJhbGciOiJIUzI1NiIsInR5cC I6IkpXVCJ9.eyJzdWIiOiIxMj M0NTY3ODkwIiwibmFtZSI6I kpvZWwgTG9yZCIsImFkbWl uIjp0cnVlLCJzY29wZSI6InBv c3RzOnJlYWQgcG9zdHM6 d3JpdGUifQ.XesR- pKdlscHfUwoKvHnACqfpe2 ywJ6t1BJKsq9rEcg
  58. 58. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Header ▸ Payload ▸ Signature eyJhbGciOiJIUzI1NiIsInR5cC I6IkpXVCJ9.eyJzdWIiOiIxMj M0NTY3ODkwIiwibmFtZSI6I kpvZWwgTG9yZCIsImFkbWl uIjp0cnVlLCJzY29wZSI6InBv c3RzOnJlYWQgcG9zdHM6 d3JpdGUifQ.XesR- pKdlscHfUwoKvHnACqfpe2 ywJ6t1BJKsq9rEcg
  59. 59. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Header eyJhbGciOiJIUzI1NiIsInR5cC I6IkpXVCJ9.eyJzdWIiOiIxMj M0NTY3ODkwIiwibmFtZSI6I kpvZWwgTG9yZCIsImFkbWl uIjp0cnVlLCJzY29wZSI6InBv c3RzOnJlYWQgcG9zdHM6 d3JpdGUifQ.XesR- pKdlscHfUwoKvHnACqfpe2 ywJ6t1BJKsq9rEcg
  60. 60. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Header eyJhbGciOiJIUzI1NiIsInR5cC I6IkpXVCJ9
  61. 61. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Header atob(‘eyJhbGciOiJIUzI1NiIsI nR5cCI6IkpXVCJ9’);
  62. 62. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Header { "alg": "HS256", "typ": "JWT" }
  63. 63. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Payload eyJhbGciOiJIUzI1NiIsInR5cC I6IkpXVCJ9.eyJzdWIiOiIxMj M0NTY3ODkwIiwibmFtZSI6I kpvZWwgTG9yZCIsImFkbWl uIjp0cnVlLCJzY29wZSI6InBv c3RzOnJlYWQgcG9zdHM6 d3JpdGUifQ.XesR- pKdlscHfUwoKvHnACqfpe2 ywJ6t1BJKsq9rEcg
  64. 64. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Payload eyJzdWIiOiIxMjM0NTY3OD kwIiwibmFtZSI6IkpvZWwgT G9yZCIsImFkbWluIjp0cnVlL CJzY29wZSI6InBvc3RzOnJl YWQgcG9zdHM6d3JpdGUi fQ
  65. 65. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Payload atob(‘eyJzdWIiOiIxMjM0NT Y3ODkwIiwibmFtZSI6IkpvZ WwgTG9yZCIsImFkbWluIjp 0cnVlLCJzY29wZSI6InBvc3R zOnJlYWQgcG9zdHM6d3J pdGUifQ’);
  66. 66. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Payload { "sub": "1234567890", "name": "Joel Lord", "admin": true, "scope": "posts:read posts:write" }
  67. 67. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Signature XesR- pKdlscHfUwoKvHnACqfpe2 ywJ6t1BJKsq9rEcg
  68. 68. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) ▸ Signature hmacsha256( `${header}.${payload}`, SECRET_KEY );
  69. 69. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) JSON WEB TOKENS (JWTS, NOT JOTS) Image: https://jwt.io
  70. 70. CODE TIME!
  71. 71. Auth Server API from flask import Flask, jsonify import os from api_auth_header import AuthError, requires_auth from flask_cors import CORS from randopeep import clickbait app = Flask(__name__) CORS(app) @app.errorhandler(AuthError) def handle_auth_error(ex): response = jsonify(ex.error) response.status_code = ex.status_code return response @app.route("/headline") def headline(): return clickbait.headline() @app.route("/protected/headline") @requires_auth def protected_headline(): return clickbait.headline("Joel Lord") if __name__ == '__main__': port = int(os.environ.get('PORT', 8888)) print("Auth server started on port %d " % port) app.run(host='0.0.0.0', port=port, debug=True) import os from flask import Flask, request, abort, redirect from jose import jwt app = Flask(__name__) users = [{"id": 1, "username": "joellord", "password": "joellord"}] @app.route("/login", methods=["GET"]) def login_form(): print("Serve form") callback_url = request.args.get("callback") return "<form method='post'>...</form>" @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) print(user) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm='HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302) if __name__ == '__main__': port = int(os.environ.get('PORT', 8080)) print("Auth server started on port %d " % port) app.run(host='0.0.0.0', port=port, debug=True) ●
  72. 72. @joel__lord #PyConSK Auth Server import os from flask import Flask, request, abort, redirect from jose import jwt app = Flask(__name__) // ...
  73. 73. @joel__lord #PyConSK Auth Server import os from flask import Flask, request, abort, redirect from jose import jwt app = Flask(__name__) // ...
  74. 74. @joel__lord #PyConSK Auth Server import os from flask import Flask, request, abort, redirect from jose import jwt app = Flask(__name__) // ...
  75. 75. @joel__lord #PyConSK Auth Server import os from flask import Flask, request, abort, redirect from jose import jwt app = Flask(__name__) // ...
  76. 76. @joel__lord #PyConSK Auth Server # imports ... users = [ { "id": 1, "username": "joellord", "password": "joellord" }, { "id": 2, "username": "guest", "password": "guest" } ]
  77. 77. @joel__lord #PyConSK Auth Server # imports ... users = [...] @app.route("/login", methods=["GET"]) def login_form(): # login form @app.route("/login", methods=["POST"]) def process_login(): # handle request
  78. 78. @joel__lord #PyConSK Auth Server # imports ... users = [...] @app.route("/login", methods=["GET"]) def login_form(): # login form @app.route("/login", methods=["POST"]) def process_login(): # handle request
  79. 79. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["GET"]) def login_form(): print("Serve form") callback_url = request.args.get("callback") return "<form method='post'><input type=hidden name=callback value='" + callback_url + "'><input type=text name=username /><input type=text name=password /><input type=submit></form>"
  80. 80. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["GET"]) def login_form(): print("Serve form") callback_url = request.args.get("callback") return "<form method='post'><input type=hidden name=callback value='" + callback_url + "'><input type=text name=username /><input type=text name=password /><input type=submit></form>"
  81. 81. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm=‘HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302)
  82. 82. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm=‘HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302)
  83. 83. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm=‘HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302)
  84. 84. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm=‘HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302)
  85. 85. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm=‘HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302)
  86. 86. @joel__lord #PyConSK Auth Server @app.route("/login", methods=["POST"]) def process_login(): username = request.form.get("username") password = request.form.get("password") callback = request.form.get("callback") if (username is "" or password is ""): abort(400) user = next((user for user in users if user["username"] == username and user["password"] == password), False) if (user == False): abort(401) token = jwt.encode({ "sub": str(user["id"]), "username": user["username"], "scope": "dostuff", "aud": "my-random-clickbait-api", "iss": "my-small-auth-server" }, "my-super-secret-key", algorithm=‘HS256') redirect_url = callback + "#access_token=" + token return redirect(redirect_url, code=302)
  87. 87. @joel__lord #PyConSK Auth Server # imports ... users = [...] @app.route("/login", methods=["GET"]) # ... @app.route("/login", methods=["POST"]) # ... if __name__ == '__main__': port = int(os.environ.get('PORT', 8080)) print("Auth server started on port %d " % port) app.run(host='0.0.0.0', port=port, debug=True)
  88. 88. @joel__lord #PyConSK API from flask import Flask, jsonify import os from api_auth_header import AuthError, requires_auth from flask_cors import CORS from randopeep import clickbait app = Flask(__name__) CORS(app)
  89. 89. @joel__lord #PyConSK API # imports @app.route("/headline") def headline(): return clickbait.headline() @app.route("/protected/headline") @requires_auth def protected_headline(): return clickbait.headline("Joel Lord")
  90. 90. @joel__lord #PyConSK API # imports @app.route("/headline") def headline(): return clickbait.headline() @app.route("/protected/headline") @requires_auth def protected_headline(): return clickbait.headline("Joel Lord")
  91. 91. @joel__lord #PyConSK API # imports @app.route("/headline") def headline(): return clickbait.headline() @app.route("/protected/headline") @requires_auth def protected_headline(): return clickbait.headline("Joel Lord")
  92. 92. @joel__lord #PyConSK API # imports … @app.route("/headline") def headline(): # … @app.route("/protected/headline") @requires_auth def protected_headline(): # … if __name__ == '__main__': port = int(os.environ.get('PORT', 8888)) print("Auth server started on port %d " % port) app.run(host='0.0.0.0', port=port, debug=True)
  93. 93. @joel__lord #PyConSK API (@requires_authfrom functools import wraps from jose import jwt from flask import _request_ctx_stack, request class AuthError(Exception): def __init__(self, error, status_code): self.error = error self.status_code = status_code def get_token_auth_header(): # Get and validate the token... return token def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): token = get_token_auth_header() try: payload = jwt.decode(token, "my-super-secret-key", algorithms="HS256") except jwt.ExpiredSignatureError: raise AuthError({"code": "token_expired", "description": "Token is expired"}, 401) # Also check claims and headers _request_ctx_stack.top.current_user = payload return f(*args, **kwargs) return decorated
  94. 94. @joel__lord #PyConSK API (@requires_authfrom functools import wraps from jose import jwt from flask import _request_ctx_stack, request class AuthError(Exception): def __init__(self, error, status_code): self.error = error self.status_code = status_code def get_token_auth_header(): # Get and validate the token... return token def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): token = get_token_auth_header() try: payload = jwt.decode(token, "my-super-secret-key", algorithms="HS256") except jwt.ExpiredSignatureError: raise AuthError({"code": "token_expired", "description": "Token is expired"}, 401) # Also check claims and headers _request_ctx_stack.top.current_user = payload return f(*args, **kwargs) return decorated
  95. 95. @joel__lord #PyConSK API (@requires_authfrom functools import wraps from jose import jwt from flask import _request_ctx_stack, request class AuthError(Exception): def __init__(self, error, status_code): self.error = error self.status_code = status_code def get_token_auth_header(): # Get and validate the token... return token def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): token = get_token_auth_header() try: payload = jwt.decode(token, "my-super-secret-key", algorithms="HS256") except jwt.ExpiredSignatureError: raise AuthError({"code": "token_expired", "description": "Token is expired"}, 401) # Also check claims and headers _request_ctx_stack.top.current_user = payload return f(*args, **kwargs) return decorated
  96. 96. @joel__lord #PyConSK API (@requires_authfrom functools import wraps from jose import jwt from flask import _request_ctx_stack, request class AuthError(Exception): def __init__(self, error, status_code): self.error = error self.status_code = status_code def get_token_auth_header(): # Get and validate the token... return token def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): token = get_token_auth_header() try: payload = jwt.decode(token, "my-super-secret-key", algorithms="HS256") except jwt.ExpiredSignatureError: raise AuthError({"code": "token_expired", "description": "Token is expired"}, 401) # Also check claims and headers _request_ctx_stack.top.current_user = payload return f(*args, **kwargs) return decorated
  97. 97. I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) DEAR DEMO GODS, PLEASE LET THIS WORK ▸ https://github.com/joellord/ secure-spa-auth0
  98. 98. DELEGATION!
  99. 99. INTRODUCING OPEN ID CONNECT!
  100. 100. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OPEN ID CONNECT ▸ Built on top of OAuth 2.0 ▸ OpenID Connect is to OpenId what JavaScript is to Java ▸ Provides Identity Tokens in JWT format ▸ Uses a /userinfo endpoint to provide this info
  101. 101. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OPEN ID CONNECT ▸ Uses the “scope” to fetch info ▸ openid ▸ Profile ▸ email ▸ address ▸ phone
  102. 102. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) OPEN ID CONNECT Image: https://openidconnect.net
  103. 103. DELEGATION!
  104. 104. @joel__lord #PyConSK I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) RESOURCES ▸ General JWT resource ▸ https://jwt.io/ ▸ Learn how OIDC works ▸ https://openidconnect.net/ ▸ Code samples ▸ http://bit.ly/idontcareaboutsecurity
  105. 105. @joel__lord joellord I DON’T CARE ABOUT SECURITY (AND NEITHER SHOULD YOU) PyCon SK March 23rd, 2019 THANK YOU !
  106. 106. TEXT
  107. 107. TEXT

×