<!-- review: finished -->

<a id="oidc-config"></a>

# 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.

<a id="architecture"></a>

## Architecture

The OIDC setup suggested here consists of:

- Angie - with Lua module support for OIDC processing
- [lua-resty-openidc](https://github.com/zmartzone/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

<a id="prerequisites"></a>

## Prerequisites

Before configuring OIDC authentication, ensure you have:

1. Angie web server with [Lua module](https://en.angie.software//angie/docs/installation/external-modules/lua.md#external-lua) support
2. Docker and Docker Compose (for deployment)
3. A Google Cloud Console project
4. OAuth2 credentials from Google

<a id="google-oauth2-setup"></a>

## Google OAuth2 Setup

To configure Google as your OIDC provider:

1. Navigate to the [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
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.

<a id="configuration-setup"></a>

## Configuration Setup

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

<a id="docker-compose-configuration"></a>

### Docker Compose Configuration

The Docker deployment uses the following configuration file:

```yaml
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](https://en.angie.software//angie/docs/installation/docker.md#docker-templated) with Lua module support
- Loads the [Lua module](https://en.angie.software//angie/docs/installation/external-modules/lua.md#external-lua) 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`](https://en.angie.software//angie/docs/configuration/oidc-sample-config.zip),
set your `client_id` and `client_secret` in `files/etc/angie/http.d/oidc.lua`,
and everything will work out of the box.

<a id="oidc-authentication-script"></a>

### OIDC Authentication Script

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

```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

<a id="angie-configuration"></a>

### Angie Configuration

Configure Angie with the necessary [location](https://en.angie.software//angie/docs/configuration/modules/http/index.md#location) blocks
for OIDC authentication.

<a id="protected-resources"></a>

#### Protected Resources

To protect resources with OIDC authentication:

```nginx
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](https://en.angie.software//angie/docs/configuration/modules/http/http_api.md#http-api)
  at `/status/`

<a id="authentication-endpoints"></a>

#### Authentication Endpoints

Configure the OAuth2 flow endpoints:

```nginx
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

<a id="internal-api-access"></a>

#### Internal API Access

Configure restricted access to the internal API:

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

This provides:

- Access to Angie's [status API](https://en.angie.software//angie/docs/configuration/modules/http/http_api.md#http-api)
- Localhost-only access (127.0.0.1)
- OIDC protection when accessed through `/internal/`

<a id="deployment-steps"></a>

## Deployment Steps

Follow these steps to deploy OIDC authentication:

<a id="configuration-update"></a>

### 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

<a id="service-startup"></a>

### Service Startup

1. Start the Docker services:
   ```console
   $ 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

<a id="security-configuration"></a>

## Security Configuration

<a id="email-domain-restriction"></a>

### Email Domain Restriction

Implement domain validation to restrict access by email domain:

```lua
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

<a id="token-management"></a>

### 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

<a id="authentication-flow"></a>

## 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`

<a id="advanced-configuration"></a>

## Advanced Configuration

To restrict access to a specific organization domain:

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

For organizations with multiple allowed domains:

```lua
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
```

<a id="user-information-access"></a>

### User Information Access

Access additional user claims from the OIDC provider:

```lua
-- 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.
