Skip to content

Instantly share code, notes, and snippets.

@honewatson
Forked from josegonzalez/access.lua
Created August 13, 2016 21:19
Show Gist options
  • Save honewatson/5cdc1c2670053c13c339c37f0b1dd715 to your computer and use it in GitHub Desktop.
Save honewatson/5cdc1c2670053c13c339c37f0b1dd715 to your computer and use it in GitHub Desktop.
Simple lua file enabling oauth support for nginx via nginx-lua and access_by_lua.
- 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)
# 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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment