Skip to content

Feature/device flow auth#227

Merged
The127 merged 10 commits intomainfrom
feature/device-flow-auth
Mar 19, 2026
Merged

Feature/device flow auth#227
The127 merged 10 commits intomainfrom
feature/device-flow-auth

Conversation

@The127
Copy link
Owner

@The127 The127 commented Mar 19, 2026

No description provided.

The127 added 9 commits March 19, 2026 10:32
Introduced `deviceFlowEnabled` to `Application` model and repository. Updated migration, mapping functions, and SQL queries to support the new property.

Signed-off-by: karo <karolin.kostial@gmail.com>
Added `OidcDeviceCodeTokenType` and `OidcUserCodeTokenType` to token types. Introduced `StoreToken` method for token service and `DeviceCodeInfo` structure for managing device code flow data. Updated `LoginInfo` to include `deviceCode`.

Signed-off-by: karo <karolin.kostial@gmail.com>
Added support for updating the `deviceFlowEnabled` property in the `PatchApplication` command and HTTP handler. Updated DTO and application update logic accordingly.

Signed-off-by: karo <karolin.kostial@gmail.com>
Registered new OIDC routes for initiating device flow, handling activation pages, and success handling.

Signed-off-by: karo <karolin.kostial@gmail.com>
Added `DeviceAuthorizationEndpoint` to OpenID configuration. Introduced support for the device code grant type and accompanying OIDC endpoints, including device flow initiation, activation, and token issuance. Updated `DeviceCodeInfo` structure and validation logic.

Signed-off-by: karo <karolin.kostial@gmail.com>
Implemented `OidcClient` to handle the device code flow, including initiating the device authorization and polling for tokens. Extended `Transport` with `NewOidcRequest` and `DoRaw` methods to support OIDC-related HTTP requests. Updated the main client interface to expose the `Oidc` client.

Signed-off-by: karo <karolin.kostial@gmail.com>
…ation

Added `PostActivate`, `VerifyPassword`, and `FinishLogin` methods to `OidcClient`. Updated `Transport` with `DoNoRedirect` to support requests without redirections. Refactored e2e tests to utilize new client methods for device flow and activation scenarios.

Signed-off-by: karo <karolin.kostial@gmail.com>
… server commands

Extended DTOs, handlers, commands, and configuration to include the `deviceFlowEnabled` property for applications.

Signed-off-by: karo <karolin.kostial@gmail.com>
…mapping

Updated audit log mapping to use `sql.NullString` for nullable string fields. Removed reliance on `pq.ByteaArray` and introduced helper functions for wrapping and unwrapping nullable values.

Signed-off-by: karo <karolin.kostial@gmail.com>
Copilot AI review requested due to automatic review settings March 19, 2026 10:58
@The127 The127 enabled auto-merge March 19, 2026 10:58
…` calls in OIDC client

Signed-off-by: karo <karolin.kostial@gmail.com>
@The127 The127 merged commit 99f9c60 into main Mar 19, 2026
9 checks passed
@The127 The127 deleted the feature/device-flow-auth branch March 19, 2026 11:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds OAuth2/OIDC Device Authorization Grant (“device flow”) support to Keyline, including server endpoints, persistence/config wiring, and client + E2E coverage to exercise the full approval/polling flow.

Changes:

  • Introduces /oidc/{vs}/device initiation, activation redirects (/activate, /activate/success), and device_code token exchange via the existing /token endpoint.
  • Adds device_flow_enabled application flag (DB migration + repository/entity/command/handler/config plumbing) to gate device flow per application.
  • Adds a Go client OIDC helper for device flow plus E2E and unit tests.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/e2e/harness.go Exposes the DI scope from the E2E harness for fixture setup.
tests/e2e/deviceflow_test.go New E2E coverage for device flow initiation, activation, polling, and one-time use semantics.
internal/services/tokens.go Adds device/user code token types and a new token storage method.
internal/server/server.go Registers new OIDC device/activation routes.
internal/repositories/postgres/auditlogs.go Fixes/adjusts audit log DB mapping (response/allowReasonType) and insert columns.
internal/repositories/postgres/applications.go Persists and updates the new device_flow_enabled application column.
internal/repositories/applications.go Adds domain field + change tracking for DeviceFlowEnabled.
internal/jsonTypes/LoginInfo.go Adds DeviceCode to login session payload to link login completion to device flow authorization.
internal/jsonTypes/DeviceCodeInfo.go Introduces KV-stored device_code metadata (status, scopes, user linkage, etc.).
internal/handlers/oidc.go Implements device flow initiation, activation redirect handlers, and device_code grant handling on /token.
internal/handlers/login.go Marks device_code as authorized during FinishLogin when login was initiated from activation.
internal/handlers/applications.go Exposes device flow enabled flag in create/patch application APIs.
internal/database/postgres/migrations/18_deviceFlow.sql Adds device_flow_enabled column to applications.
internal/config/config.go Adds DeviceFlowEnabled to initial project application config.
internal/commands/PatchApplication.go Allows patching DeviceFlowEnabled via command handler.
internal/commands/CreateVirtualServer.go Applies DeviceFlowEnabled when seeding applications for a virtual server.
internal/commands/CreateApplication.go Sets DeviceFlowEnabled on application creation.
cmd/api/main.go Maps config DeviceFlowEnabled into app seed command payload.
client/transport.go Adds OIDC request helper + raw/no-redirect request execution helpers.
client/oidc_test.go Unit tests for the new client device flow methods.
client/oidc.go Implements client-side device flow calls (begin, poll, activate, login steps).
client/client.go Exposes Oidc() client surface.

if application == nil {
utils.HandleHttpError(w, fmt.Errorf("application not found"))
return
}
Comment on lines +128 to +133
noRedirectClient := &http.Client{
Transport: t.client.Transport,
CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
},
}
Comment on lines +2019 to +2025
http.Error(w, "Invalid or expired device code. Please request a new one.", http.StatusNotFound)
return
}

deviceCodeInfoString, err := tokenService.GetToken(ctx, services.OidcDeviceCodeTokenType, deviceCode)
if err != nil {
http.Error(w, "Invalid or expired device code. Please request a new one.", http.StatusNotFound)
Comment on lines 34 to +38
GenerateAndStoreToken(ctx context.Context, tokenType TokenType, value string, expiration time.Duration) (string, error)
UpdateToken(ctx context.Context, tokenType TokenType, token string, value string, expiration time.Duration) error
GetToken(ctx context.Context, tokenType TokenType, token string) (string, error)
DeleteToken(ctx context.Context, tokenType TokenType, token string) error
StoreToken(ctx context.Context, tokenType TokenType, token string, value string, expiration time.Duration) error
}
return string(result)
}

Comment on lines +1883 to +1887
err = tokenService.DeleteToken(ctx, services.OidcDeviceCodeTokenType, deviceCode)
if err != nil {
utils.HandleHttpError(w, fmt.Errorf("deleting device code: %w", err))
return
}
Comment on lines +65 to +67
oidcRouter.HandleFunc("/activate", handlers.GetActivatePage).Methods(http.MethodGet)
oidcRouter.HandleFunc("/activate", handlers.PostActivatePage).Methods(http.MethodPost)
oidcRouter.HandleFunc("/activate/success", handlers.ActivateSuccess).Methods(http.MethodGet)
Comment on lines +1714 to +1718
func BeginDeviceFlow(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
scope := middlewares.GetScope(ctx)

err := r.ParseForm()
Comment on lines +568 to +572
}

if err := tokenService.UpdateToken(ctx, services.OidcDeviceCodeTokenType, loginInfo.DeviceCode, string(updatedInfoJson), 10*time.Minute); err != nil {
utils.HandleHttpError(w, fmt.Errorf("updating device code info: %w", err))
return
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants