SkyLothar / lua-resty-jwt

JWT For The Great Openresty
Apache License 2.0
513 stars 179 forks source link

support for different statuses from claim_specs - e.g. 401 vs 403 #73

Closed agilezebra closed 4 years ago

agilezebra commented 6 years ago

In our requirements, we need to differentiate between: a) unauthenticated users: those that have not logged in yet, or those with expired sessions: return HTTP 401, so that they are redirected to a login page b) unauthorized users: those trying to access API endpoints or resources that, although they are authenticated, they don’t have permission for: return HTTP 403, indicating they don’t have permission (and logging in again won’t help). I have been able to achieve this with this codebase as it stands, with the multiple calls to jwt:verify, but this seems a bit inefficient. The attached PR allows us to do the to validate two sets of claims in one call and differentiate between 401 and 403 statuses (or any other status for that matter. With these changes I'm not able to do the following:


local header = ngx.var.http_Authorization
if header then
    _, _, token = string.find(header, "Bearer%s+(.+)")
else
    token = nil
end

if token == nil then
    ngx.status = ngx.HTTP_UNAUTHORIZED
    ngx.header.content_type = "application/json; charset=utf-8"
    ngx.say("{error: \"missing JWT token or Authorization header\"}")
    ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

local validators = require "resty.jwt-validators"
validators.set_system_leeway(15) -- time in seconds

-- Verify the token is present and valid - 401 if not
local authenticated_claims = {
    exp = validators.is_not_expired()
}

-- Verify the token is authorized for this resouce - 403 if not
local authorized_claims = {
    iss = validators.equals("https://accounts.google.com"),
    hd = validators.equals("examplecorp.com"),
    __status = ngx.HTTP_FORBIDDEN
}

local result = jwt:verify(os.getenv("JWT_SECRET"), token, authenticated_claims, authorized_claims)

if not result.verified then
    ngx.status = result.status
    ngx.log(ngx.WARN, result.reason)
    ngx.header.content_type = "application/json; charset=utf-8"
    ngx.say("{error: \"" .. result.reason .. "\"}")
    ngx.exit(ngx.status)
end