Skip to content

support OpenID Connect Front Channel Logout #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
endpoint if this has not been done before in order to detect the URI
of the userinfo endpoint

03/27/2020
- added a function that implements OpenID Connect Front Channel Logout

02/06/2020
- ability to disable keepalive from lua-resty-http
By disabling keepalive we disable the native connection pool,
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,43 @@ local res, err, target, session = require("resty.openidc").authenticate(opts)
session:close()
```

## Front-Channel Logout

The `front_channel_logout` function can be used as a content handler
to implement [OpenID Connect Front-Channel
Logout](https://openid.net/specs/openid-connect-frontchannel-1_0.html).

```nginx
...
location /fc-logout {
content_by_lua_block {
local opts = {
-- session_required = true,
-- If this parameter is not set or set to true, requests to
-- the front channel logout URI must include the iss and sid
-- parameters.
-- This also requires id_tokens to be stored inside of the session.
-- Default is true

-- opts.iss = '...',
-- if session_required is false the iss parameter can be
-- compared to a hard-coded iss value.
-- Default is nil

-- downstream_logout = { 'other-uri', 'yet-another-uri' }
-- can contain a table of URIs to be notified via new iframes
-- included inside of the response
-- Default is no downstream logout URIs at all
}
require("resty.openidc").front_channel_logout(opts)
}
}
```

The `front_channel_logout` accepts as an optional second argument a
table that is passed to `session.open` in order to read the existing
session.

## Sample Configuration for OAuth 2.0 JWT Token Validation

Sample `nginx.conf` configuration for verifying Bearer JWT Access Tokens against a pre-configured secret/key.
Expand Down
58 changes: 58 additions & 0 deletions lib/resty/openidc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1741,4 +1741,62 @@ function openidc.set_logging(new_log, new_levels)
WARN = new_levels.WARN and new_levels.WARN or ngx.WARN
end

function openidc.front_channel_logout(opts, session_opts)
local session, is_existing = r_session.open(session_opts)
local logout_success = true
log(DEBUG, 'Front-Channel Logout invoked')
if not is_existing then
log(WARN, 'no session present, nothing to do')
logout_success = false
else
if not session.started then
session:start()
end
local args = ngx.req.get_uri_args()
if not (args.sid and args.iss) then
log(DEBUG, 'Front-Channel Logout invoked without sid or iss')
if opts.session_required == nil or opts.session_required then
log(ERROR, 'deny logout as the required session information is missing')
logout_success = false
end
else
local id_token = session.data.id_token
if (opts.session_required == nil or opts.session_required) and not id_token then
log(ERROR, 'as id_token is not stored in session and session is required')
logout_success = false
end
if id_token and id_token.sid and id_token.sid ~= args.sid then
log(ERROR, 'Front-Channel Logout sid argument is different from sid stored in id_token')
logout_success = false
end
if id_token and id_token.iss and id_token.iss ~= args.iss then
log(ERROR, 'Front-Channel Logout iss argument is different from iss stored in id_token')
logout_success = false
end
if not id_token and opts and opts.iss and opts.iss ~= args.iss then
log(ERROR, 'Front-Channel Logout iss argument is different from iss stored in opts')
logout_success = false
end
end
end
ngx.header['Cache-Control'] = 'no-cache, no-store'
ngx.header['Pragma'] = 'no-cache'
ngx.header.content_type = 'text/html'
if logout_success then
log(DEBUG, 'Performing Front-Channel Logout')
session:destroy()
end
ngx.print('<html><body>')
if logout_success and opts.downstream_logout then
local downstream = type(opts.downstream_logout) == 'table' and opts.downstream_logout
or { opts.downstream_logout }
local _, d
for _, d in pairs(downstream) do
log(DEBUG, 'also notify ', d)
ngx.print('<iframe src="' .. d .. '">')
end
end
ngx.print('</body></html>')
end

return openidc
Loading