이제 우리는 JWT가 client로부터 server에 어떻게 전송하는지 이해해야 한다. 그러기 위해서 Authorization Header를 사용할 것이다. Autorization header를 서버에 보내는 subsequent request들의 일부분으로 포함시킨다.
사실 authorization header는 그냥 string이다. JWT에 가장 일반적으로 사용되는 bearer라는 특정 키워드가 포함되어 있다. 이것은 어떤 타입의 token이 autorization header에 포함되었는지를 나타낸다. Bearer와 token은 space로 나누어진다.
bearer token으로서 JWT와 함께 authorization headers를 Postman과 Flask를 이용하여 어떻게 전송할지 확인해보자.
form flask import Flask, request
app = Flask(__name__)
@app.route('/headers')
def headers():
# UNPACK THE REQUEST HEADER
auth_header = request.headers['Authorization']
header_parts = auth_header.split(' ')[1]
print(header_parts)
return 'not implemented'
from flask import Flask, request, abort
from functools import wraps
app = Flask(__name__)
def get_token_auth_header():
if 'Authorization' not in request.headers:
abort(401)
auth_header = request.headers['Authorization']
header_parts = auth_header.split(' ')
if len(header_parts) != 2:
abort(401)
elif header_parts[0].lower() != 'bearer':
abort(401)
return(header_parts[1])
def requires_auth(f):
@wraps(f)
def warpper(*args, **kwargs):
jwt = get_token_auth_header()
return f(jwt, *args, **kwargs)
return warpper
@app.route('/headers')
@requires_auth
def headers(jwt):
# @TODO unpack the request header
print(jwt)
return 'not implemented'
from flask import Flask, request, abort
import json
from functools import wraps
from jose import jwt
from urllib.request import urlopen
app = Flask(__name__)
AUTH0_DOMAIN = 'hyunlang.auth0.com'
ALGORITHMS = ['RS256']
API_AUDIENCE = 'image'
class AuthError(Exception):
def __init__(self, error, status_code):
self.error = error
self.status_code = status_code
def get_token_auth_header():
"""Obtains the Access Token from the Authorization Header
"""
auth = request.headers.get('Authorization', None)
if not auth:
raise AuthError({
'code': 'authorization_header_missing',
'description': 'Authorization header is expected.'
}, 401)
parts = auth.split()
if parts[0].lower() != 'bearer':
raise AuthError({
'code': 'invalid_header',
'description': 'Authorization header must start with "Bearer".'
}, 401)
elif len(parts) == 1:
raise AuthError({
'code': 'invalid_header',
'description': 'Token not found.'
}, 401)
elif len(parts) > 2:
raise AuthError({
'code': 'invalid_header',
'description': 'Authorization header must be bearer token.'
}, 401)
token = parts[1]
return token
def verify_decode_jwt(token):
jsonurl = urlopen(f'https://{AUTH0_DOMAIN}/.well-known/jwks.json')
jwks = json.loads(jsonurl.read())
unverified_header = jwt.get_unverified_header(token)
rsa_key = {}
if 'kid' not in unverified_header:
raise AuthError({
'code': 'invalid_header',
'description': 'Authorization malformed.'
}, 401)
for key in jwks['keys']:
if key['kid'] == unverified_header['kid']:
rsa_key = {
'kty': key['kty'],
'kid': key['kid'],
'use': key['use'],
'n': key['n'],
'e': key['e']
}
if rsa_key:
try:
payload = jwt.decode(
token,
rsa_key,
algorithms=ALGORITHMS,
audience=API_AUDIENCE,
issuer='https://' + AUTH0_DOMAIN + '/'
)
return payload
except jwt.ExpiredSignatureError:
raise AuthError({
'code': 'token_expired',
'description': 'Token expired.'
}, 401)
except jwt.JWTClaimsError:
raise AuthError({
'code': 'invalid_claims',
'description': 'Incorrect claims. Please, check the audience and issuer.'
}, 401)
except Exception:
raise AuthError({
'code': 'invalid_header',
'description': 'Unable to parse authentication token.'
}, 400)
raise AuthError({
'code': 'invalid_header',
'description': 'Unable to find the appropriate key.'
}, 400)
def requires_auth(f):
@wraps(f)
def wrapper(*args, **kwargs):
token = get_token_auth_header()
try:
payload = verify_decode_jwt(token)
except:
abort(401)
return f(payload, *args, **kwargs)
return wrapper
@app.route('/headers')
@requires_auth
def headers(payload):
print(payload)
return 'Access Granted'