public
Last active

Simple lua file enabling oauth support for nginx via nginx-lua and access_by_lua.

  • Download Gist
access.lua
Lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
- certain endpoints are always blocked
if nginx_uri == "/_access_token" or nginx_uri == "/_me" then
ngx.exit(403)
end
 
-- import requirements
local cjson = require "cjson"
 
-- setup some app-level vars
local app_id = "APP_ID"
local app_secret = "APP_SECRET"
 
local args = ngx.req.get_uri_args()
if args.error and args.error == "access_denied" then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.say("{"status": 401, "message": ""..args.error_description..""}")
return ngx.exit(ngx.HTTP_OK)
end
 
local access_token = ngx.var.cookie_SGAccessToken
if access_token then
ngx.header["Set-Cookie"] = "SGAccessToken="..access_token.."; path=/;Max-Age=3000"
end
 
-- first lets check for a code where we retrieve
-- credentials from the api
if not access_token or args.code then
if args.code then
-- internal-oauth:1337/access_token
local res = ngx.location.capture("/_access_token?client_id="..app_id.."&client_secret="..app_secret.."&code="..args.code)
 
-- kill all invalid responses immediately
if res.status ~= 200 then
ngx.status = res.status
ngx.say(res.body)
ngx.exit(ngx.HTTP_OK)
end
 
-- decode the token
local text = res.body
local json = cjson.decode(text)
access_token = json.access_token
end
 
-- both the cookie and proxy_pass token retrieval failed
if not access_token then
-- Track the endpoint they wanted access to so we can transparently redirect them back
ngx.header["Set-Cookie"] = "SGRedirectBack="..nginx_uri.."; path=/;Max-Age=120"
 
-- Redirect to the /oauth endpoint, request access to ALL scopes
return ngx.redirect("internal-oauth:1337/oauth?client_id="..app_id.."&scope=all")
end
end
 
-- ensure we have a user with the proper access app-level
-- internal-oauth:1337/accessible
local res = ngx.location.capture("/_accessible", {args = { access_token = access_token } } )
if res.status ~= 200 then
-- delete their bad token
ngx.header["Set-Cookie"] = "SGAccessToken=deleted; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"
 
-- Redirect 403 forbidden back to the oauth endpoint, as their stored token was somehow bad
if res.status == 403 then
return ngx.redirect("https://seatgeek.com/oauth?client_id="..app_id.."&scope=all")
end
 
-- Disallow access
ngx.status = res.status
ngx.say("{"status": 503, "message": "Error accessing api/me for credentials"}")
return ngx.exit(ngx.HTTP_OK)
end
 
local json = cjson.decode(res.body)
-- Ensure we have the minimum for access_level to this resource
if json.access_level < 255 then
-- Expire their stored token
ngx.header["Set-Cookie"] = "SGAccessToken=deleted; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"
 
-- Disallow access
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.say("{"status": 403, "message": "USER_ID"..json.user_id.." has no access to this resource"}")
return ngx.exit(ngx.HTTP_OK)
end
 
-- Store the access_token within a cookie
ngx.header["Set-Cookie"] = "SGAccessToken="..access_token.."; path=/;Max-Age=3000"
 
-- Support redirection back to your request if necessary
local redirect_back = ngx.var.cookie_SGRedirectBack
if redirect_back then
ngx.header["Set-Cookie"] = "SGRedirectBack=deleted; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"
return ngx.redirect(redirect_back)
end
 
-- Set some headers for use within the protected endpoint
ngx.req.set_header("X-USER-ACCESS-LEVEL", json.access_level)
ngx.req.set_header("X-USER-EMAIL", json.email)
nginx-site
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
# The app we are proxying to
upstream production-app {
server localhost:8080;
}
 
# The internal oauth provider
upstream internal-oauth {
server localhost:1337;
}
 
server {
listen 80;
server_name private.example.com;
root /apps;
charset utf-8;
 
# This will run for everything but subrequests
access_by_lua_file "/etc/nginx/access.lua";
 
# Used in a subrequest
location /_access_token { proxy_pass http://internal-oauth/oauth/access_token; }
location /_user { proxy_pass http://internal-oauth/user; }
 
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_max_temp_file_size 0;
 
if (!-f $request_filename) {
proxy_pass http://production-app;
break;
}
}
 
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.