OIDC Authentication Setup#

This guide explains how to set up OpenID Connect (OIDC) authentication using Google as the identity provider and Angie web server with Lua scripting.

The implementation protects internal endpoints with OAuth2/OIDC authentication and demonstrates one way to restrict access based on email domains. This is just one example approach; you can implement access control however you prefer, such as maintaining allowlists of specific users, checking for realm membership or group attributes in the provider response, or using custom claims from your private IAM system.

Tip

This OIDC implementation provides a foundation for authentication but should be adapted for production use with proper security measures, monitoring, and compliance with your organization's security policies.

Architecture#

The OIDC setup suggested here consists of:

  • Angie - with Lua module support for OIDC processing

  • lua-resty-openidc - OpenResty Lua library for OIDC authentication

  • Google OAuth2 - Identity provider for user authentication

  • Docker Compose - Used in this example for rapid startup only; use whatever deployment approach you prefer in production

Prerequisites#

Before configuring OIDC authentication, ensure you have:

  1. Angie web server with Lua module support

  2. Docker and Docker Compose (for deployment)

  3. A Google Cloud Console project

  4. OAuth2 credentials from Google

Google OAuth2 Setup#

To configure Google as your OIDC provider:

  1. Navigate to the Google Cloud Console

  2. Create a new project or select an existing one

  3. Configure the OAuth consent screen for your project (External or Internal) and publish it so users can authenticate

  4. Create OAuth2 credentials:

    • Application type: Web application

    • Authorized redirect URIs: http://localhost/auth/callback

  5. Save your client_id and client_secret for configuration

Note

Standard Google Identity Services already support OIDC; the legacy Google+ API is not required. Enable additional Google APIs only if your application needs their data.

Configuration Setup#

Let's start with the configuration files needed for the OIDC setup.

Docker Compose Configuration#

The Docker deployment uses the following configuration file:

docker-compose.yml#
services:
  angie:
    image: docker.angie.software/angie:templated
    environment:
      ANGIE_LOAD_MODULES: "lua"
    ports:
      - 80:80
    volumes:
      - ./files/etc/angie/http.d:/etc/angie/http.d

This configuration does the following:

  • Uses the templated Angie image with Lua module support

  • Loads the Lua module for OIDC functionality

  • Maps port 80 for HTTP access

  • Mounts configuration files from local directory

For a plug-and-play demo, download the OIDC quick-start bundle, set your client_id and client_secret in files/etc/angie/http.d/oidc.lua, and everything will work out of the box.

OIDC Authentication Script#

Create an OIDC authentication script that handles the authentication logic using the lua-resty-openidc library:

/etc/angie/http.d/oidc.lua#
access_by_lua_block {
    local res, err = require("resty.openidc").authenticate({
        redirect_uri = "http://localhost/auth/callback",
        discovery = "https://accounts.google.com/.well-known/openid-configuration",
        logout_path = "/auth/logout",
        redirect_after_logout_uri = "/auth/logged-out",
        revoke_tokens_on_logout = true,
        client_id = "YOUR_CLIENT_ID",
        client_secret = "YOUR_CLIENT_SECRET"
    })
}

Configuration parameters:

  • redirect_uri: Callback URL after successful authentication

  • discovery: Google's OIDC discovery endpoint

  • logout_path: Path for user logout

  • redirect_after_logout_uri: Redirect destination after logout

  • revoke_tokens_on_logout: Revoke tokens on logout for security

  • client_id and client_secret: Your Google OAuth2 credentials

Angie Configuration#

Configure Angie with the necessary location blocks for OIDC authentication.

Protected Resources#

To protect resources with OIDC authentication:

location /internal/ {
    include /etc/angie/http.d/oidc.lua;
    proxy_pass http://127.0.0.1/status/;
}

This configuration does the following:

  • Protects the /internal/ path with OIDC authentication

  • Proxies authenticated requests to the internal API at /status/

Authentication Endpoints#

Configure the OAuth2 flow endpoints:

location /auth/callback {
    include /etc/angie/http.d/oidc.lua;
}

location /auth/logout {
    include /etc/angie/http.d/oidc.lua;
}

location /auth/logged-out {
    default_type text/plain;
    return 200 "You have been logged out. Bye!";
}

Endpoint functions:

  • /auth/callback: Handles OAuth2 callback from Google

  • /auth/logout: Initiates user logout

  • /auth/logged-out: Landing page after successful logout

Internal API Access#

Configure restricted access to the internal API:

location /status/ {
    api     /status/;
    allow   127.0.0.1;
    deny    all;
}

This provides:

  • Access to Angie's status API

  • Localhost-only access (127.0.0.1)

  • OIDC protection when accessed through /internal/

Deployment Steps#

Follow these steps to deploy OIDC authentication:

Configuration Update#

  1. Update OAuth2 credentials in your OIDC Lua script:

    Replace the placeholder values in oidc.lua:

    • client_id with your Google OAuth2 client ID

    • client_secret with your Google OAuth2 client secret

Service Startup#

  1. Start the Docker services:

    $ docker-compose up -d
    
  2. Verify the deployment:

    • Navigate to http://localhost/internal/

    • You should be redirected to Google for authentication

    • After successful login, you'll access the protected content

Security Configuration#

Email Domain Restriction#

Implement domain validation to restrict access by email domain:

if not string.match(res.user.email, "gmail.com$") then
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

For production environments, consider the following:

  • Replacing gmail.com with your organization's domain

  • Implementing a whitelist of allowed email addresses

  • Adding role-based access control

Token Management#

The OIDC implementation includes security features:

  • Tokens are automatically revoked on logout (revoke_tokens_on_logout = true)

  • Sessions are managed securely by the lua-resty-openidc library

  • All authentication flows follow OAuth2/OIDC security best practices

Warning

For production deployments:

  • Always use HTTPS for OAuth2 callbacks

  • Store client secrets securely, never in version control

  • Implement proper session timeouts and renewal policies

  • Monitor authentication logs for security events

Authentication Flow#

The OIDC authentication flow follows standard OAuth2/OIDC procedures:

  1. User accesses a protected URL (e.g., http://localhost/internal/)

  2. If not authenticated, user is redirected to Google OAuth2

  3. User authenticates with Google credentials

  4. Google redirects back to /auth/callback with authorization code

  5. Server exchanges code for access token and ID token

  6. User information is validated (including email domain check)

  7. User is granted access to protected resource

The logout process ensures secure session termination:

  1. User navigates to http://localhost/auth/logout

  2. Tokens are revoked at Google's OAuth2 endpoint

  3. Local session data is cleared

  4. User is redirected to /auth/logged-out

Advanced Configuration#

To restrict access to a specific organization domain:

if not string.match(res.user.email, "yourcompany.com$") then
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

For organizations with multiple allowed domains:

local allowed_domains = {"company1.com", "company2.com", "gmail.com"}
local email_valid = false

for _, domain in ipairs(allowed_domains) do
    if string.match(res.user.email, domain .. "$") then
        email_valid = true
        break
    end
end

if not email_valid then
    ngx.exit(ngx.HTTP_FORBIDDEN)
end

User Information Access#

Access additional user claims from the OIDC provider:

-- Access user information from ID token
local user_name = res.user.name
local user_picture = res.user.picture
local user_locale = res.user.locale
local user_email = res.user.email

These values can be used for logging, personalization, or additional access control decisions.