Add OAuth2/OpenID Connect authorization server
Implement a full OAuth2 2.0 and OpenID Connect 1.0 authorization server with support for authorization code flow (with PKCE), refresh token rotation, device authorization grant, dynamic client registration, token introspection, and token revocation. Includes database schema, coredata layer, service logic, HTTP handlers, OIDC discovery endpoint, and JWKS publishing. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
107
pkg/coredata/migrations/20260406T112100Z.sql
Normal file
107
pkg/coredata/migrations/20260406T112100Z.sql
Normal file
@@ -0,0 +1,107 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted, provided that the above
|
||||
-- copyright notice and this permission notice appear in all copies.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-- OAuth2 Authorization Server tables
|
||||
|
||||
CREATE TYPE oauth2_client_visibility AS ENUM ('private', 'public');
|
||||
CREATE TYPE oauth2_client_token_endpoint_auth_method AS ENUM ('client_secret_basic', 'client_secret_post', 'none');
|
||||
CREATE TYPE oauth2_device_code_status AS ENUM ('pending', 'authorized', 'denied', 'expired');
|
||||
|
||||
CREATE TABLE iam_oauth2_clients (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
organization_id TEXT NOT NULL,
|
||||
client_secret_hash BYTEA,
|
||||
client_name TEXT NOT NULL,
|
||||
visibility oauth2_client_visibility NOT NULL,
|
||||
redirect_uris TEXT[] NOT NULL,
|
||||
scopes TEXT[] NOT NULL,
|
||||
grant_types TEXT[] NOT NULL,
|
||||
response_types TEXT[] NOT NULL,
|
||||
token_endpoint_auth_method oauth2_client_token_endpoint_auth_method NOT NULL,
|
||||
logo_uri TEXT,
|
||||
client_uri TEXT,
|
||||
contacts TEXT[],
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE iam_oauth2_authorization_codes (
|
||||
id TEXT PRIMARY KEY,
|
||||
client_id TEXT NOT NULL REFERENCES iam_oauth2_clients(id),
|
||||
identity_id TEXT NOT NULL,
|
||||
redirect_uri TEXT NOT NULL,
|
||||
scopes TEXT[] NOT NULL,
|
||||
code_challenge TEXT,
|
||||
code_challenge_method TEXT,
|
||||
nonce TEXT,
|
||||
auth_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE iam_oauth2_access_tokens (
|
||||
id TEXT PRIMARY KEY,
|
||||
hashed_value BYTEA NOT NULL,
|
||||
client_id TEXT NOT NULL REFERENCES iam_oauth2_clients(id),
|
||||
identity_id TEXT NOT NULL,
|
||||
scopes TEXT[] NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
CONSTRAINT iam_oauth2_access_tokens_hashed_value_unique UNIQUE (hashed_value)
|
||||
);
|
||||
|
||||
CREATE TABLE iam_oauth2_refresh_tokens (
|
||||
id TEXT PRIMARY KEY,
|
||||
hashed_value BYTEA NOT NULL,
|
||||
client_id TEXT NOT NULL REFERENCES iam_oauth2_clients(id),
|
||||
identity_id TEXT NOT NULL,
|
||||
scopes TEXT[] NOT NULL,
|
||||
access_token_id TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
revoked_at TIMESTAMP WITH TIME ZONE,
|
||||
CONSTRAINT iam_oauth2_refresh_tokens_hashed_value_unique UNIQUE (hashed_value)
|
||||
);
|
||||
|
||||
CREATE TABLE iam_oauth2_device_codes (
|
||||
id TEXT PRIMARY KEY,
|
||||
device_code_hash BYTEA NOT NULL,
|
||||
user_code TEXT NOT NULL,
|
||||
client_id TEXT NOT NULL REFERENCES iam_oauth2_clients(id),
|
||||
scopes TEXT[] NOT NULL,
|
||||
identity_id TEXT,
|
||||
status oauth2_device_code_status NOT NULL,
|
||||
last_polled_at TIMESTAMP WITH TIME ZONE,
|
||||
poll_interval INT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
CONSTRAINT iam_oauth2_device_codes_device_code_hash_unique UNIQUE (device_code_hash),
|
||||
CONSTRAINT iam_oauth2_device_codes_user_code_unique UNIQUE (user_code)
|
||||
);
|
||||
|
||||
CREATE TABLE iam_oauth2_consents (
|
||||
id TEXT PRIMARY KEY,
|
||||
identity_id TEXT NOT NULL,
|
||||
client_id TEXT NOT NULL REFERENCES iam_oauth2_clients(id),
|
||||
scopes TEXT[] NOT NULL,
|
||||
redirect_uri TEXT NOT NULL,
|
||||
code_challenge TEXT NOT NULL,
|
||||
code_challenge_method TEXT NOT NULL,
|
||||
nonce TEXT NOT NULL,
|
||||
state TEXT NOT NULL,
|
||||
approved BOOLEAN NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL
|
||||
);
|
||||
2
pkg/coredata/migrations/20260406T112200Z.sql
Normal file
2
pkg/coredata/migrations/20260406T112200Z.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE iam_oauth2_consents
|
||||
ADD COLUMN session_id TEXT NOT NULL REFERENCES iam_sessions(id);
|
||||
49
pkg/coredata/migrations/20260411T120000Z.sql
Normal file
49
pkg/coredata/migrations/20260411T120000Z.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted, provided that the above
|
||||
-- copyright notice and this permission notice appear in all copies.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-- Allow system-level OAuth2 clients that don't belong to any tenant or
|
||||
-- organization (e.g. the Probo CLI).
|
||||
ALTER TABLE iam_oauth2_clients ALTER COLUMN tenant_id DROP NOT NULL;
|
||||
ALTER TABLE iam_oauth2_clients ALTER COLUMN organization_id DROP NOT NULL;
|
||||
|
||||
-- Well-known OAuth2 client for the Probo CLI (prb).
|
||||
-- This client is hardcoded in the CLI binary and used for the device
|
||||
-- authorization flow. Same pattern as GitHub CLI + GitHub Enterprise Server.
|
||||
INSERT INTO iam_oauth2_clients (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
client_name,
|
||||
visibility,
|
||||
redirect_uris,
|
||||
scopes,
|
||||
grant_types,
|
||||
response_types,
|
||||
token_endpoint_auth_method,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
'AAAAAAAAAAAASwAAAAAAAAAAcHJiY2xp',
|
||||
NULL,
|
||||
NULL,
|
||||
'Probo CLI',
|
||||
'public',
|
||||
'{}',
|
||||
'{openid,profile,email}',
|
||||
'{urn:ietf:params:oauth:grant-type:device_code,refresh_token}',
|
||||
'{code}',
|
||||
'none',
|
||||
NOW(),
|
||||
NOW()
|
||||
);
|
||||
20
pkg/coredata/migrations/20260413T232000Z.sql
Normal file
20
pkg/coredata/migrations/20260413T232000Z.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted, provided that the above
|
||||
-- copyright notice and this permission notice appear in all copies.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
-- Add offline_access scope to the Probo CLI OAuth2 client so the device
|
||||
-- authorization flow can request refresh tokens.
|
||||
UPDATE iam_oauth2_clients
|
||||
SET scopes = '{openid,profile,email,offline_access}',
|
||||
updated_at = NOW()
|
||||
WHERE id = 'AAAAAAAAAAAASwAAAAAAAAAAcHJiY2xp';
|
||||
19
pkg/coredata/migrations/20260414T083800Z.sql
Normal file
19
pkg/coredata/migrations/20260414T083800Z.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted, provided that the above
|
||||
-- copyright notice and this permission notice appear in all copies.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ALTER TABLE iam_oauth2_consents
|
||||
ADD COLUMN IF NOT EXISTS device_code_id TEXT;
|
||||
|
||||
ALTER TABLE iam_oauth2_consents
|
||||
ALTER COLUMN redirect_uri DROP NOT NULL;
|
||||
17
pkg/coredata/migrations/20260414T140000Z.sql
Normal file
17
pkg/coredata/migrations/20260414T140000Z.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted, provided that the above
|
||||
-- copyright notice and this permission notice appear in all copies.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ALTER TABLE iam_oauth2_authorization_codes
|
||||
ADD COLUMN IF NOT EXISTS redeemed_at TIMESTAMPTZ,
|
||||
ADD COLUMN IF NOT EXISTS access_token_id TEXT;
|
||||
20
pkg/coredata/migrations/20260416T120000Z.sql
Normal file
20
pkg/coredata/migrations/20260416T120000Z.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||
-- purpose with or without fee is hereby granted, provided that the above
|
||||
-- copyright notice and this permission notice appear in all copies.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
-- PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ALTER TABLE iam_oauth2_authorization_codes
|
||||
ADD COLUMN IF NOT EXISTS hashed_value BYTEA;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS iam_oauth2_authorization_codes_hashed_value_unique
|
||||
ON iam_oauth2_authorization_codes (hashed_value)
|
||||
WHERE hashed_value IS NOT NULL;
|
||||
Reference in New Issue
Block a user