Skip to content

implementing authorization code flow using zitadel library#92

Open
aaishwarya6694 wants to merge 2 commits intomainfrom
task/implement-zitadel-lib
Open

implementing authorization code flow using zitadel library#92
aaishwarya6694 wants to merge 2 commits intomainfrom
task/implement-zitadel-lib

Conversation

@aaishwarya6694
Copy link
Copy Markdown
Contributor

@aaishwarya6694 aaishwarya6694 commented Nov 7, 2025

Summary by CodeRabbit

  • Chores

    • Updated OpenID Connect dependencies and authentication libraries.
    • Switched to direct OIDC discovery using the service HTTP client for provider configuration.
    • Strengthened issuer validation (rejects plain HTTP when disallowed) and improved error messages.
    • Adjusted discovery caching and internal handling for compatibility with the updated OIDC flow.
  • Bug Fixes

    • Improved reliability of token exchange and key retrieval during authentication.

@sonarqubecloud
Copy link
Copy Markdown

@alienvspredator
Copy link
Copy Markdown
Contributor

Could you rebase the branch on the latest main?

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f987ce80-dda6-4517-9fe1-e0bc42078799

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Replaced previous OIDC config usage with Zitadel OIDC v3 discovery types; getOpenIDConfig now performs direct discovery with issuer URL parsing/validation and explicit HTTP client selection; go.mod updated to add Zitadel OIDC and related indirect dependencies.

Changes

Cohort / File(s) Summary
Dependency updates
go.mod
Added github.com/zitadel/oidc/v3 v3.45.5, golang.org/x/oauth2 v0.35.0; added indirect deps github.com/gorilla/securecookie v1.1.2, github.com/muhlemmer/gu v0.3.1, github.com/zitadel/logging v0.7.0, github.com/zitadel/schema v1.3.2; bumped indirect github.com/sirupsen/logrus to v1.9.4.
Session manager — signatures & imports
internal/session/manager.go
Switched internal helper parameter types to Zitadel's DiscoveryConfiguration (*zitadeloidc.DiscoveryConfiguration); replaced import github.com/openkcm/common-sdk/pkg/oidc with github.com/zitadel/oidc/v3/pkg/oidc (aliased zitadeloidc); updated methods reading AuthorizationEndpoint, JwksURI, and TokenEndpoint to use new type.
OIDC discovery & cache logic
internal/session/openid.go
Changed getOpenIDConfig to return *zitadeloidc.DiscoveryConfiguration; added issuer URL parsing/validation (reject http when disallowed); switched from provider-based retrieval to direct client.Discover(ctx, issuerURL, httpClient) using transport from m.newCreds("").Transport(); updated cache type assertions and error wrapping.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Manager
    participant Cache
    participant HTTPClient as HTTP Client
    participant Discover as Zitadel Discover

    Caller->>Manager: request OpenID config (issuer)
    Manager->>Cache: lookup discovery config (issuer)
    alt cache miss
        Manager->>HTTPClient: choose http.Client (m.newCreds("").Transport())
        Manager->>Discover: client.Discover(ctx, issuerURL, HTTPClient)
        Discover-->>Manager: DiscoveryConfiguration / error
        Manager->>Cache: store DiscoveryConfiguration
    end
    Manager-->>Caller: return DiscoveryConfiguration / error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Poem

🐰 I hopped to Zitadel's glen by night,

I parsed the issuer by soft moonlight,
Picked a client, fetched keys with care,
Cached the map and danced on air,
A cheerful rabbit hums: "All set and bright!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, but the template requires sections like 'What this PR does', 'Special notes', and 'Release note'. The description is completely missing. Add a detailed description following the template: include what the PR does (migrating OIDC configuration), special notes for reviewers, and release notes or 'NONE' if not applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: implementing authorization code flow using the Zitadel library, which aligns with the changeset that migrates from openkcm OIDC to Zitadel OIDC library.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/session/manager.go (2)

186-189: ⚠️ Potential issue | 🟠 Major

Missing resp.Body.Close() call.

The response body is decoded but never closed, which will leak connections over time. Compare with exchangeCode (line 618) which properly defers closing the body.

🔧 Proposed fix to close response body
 	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("executing an http request: %w", err)
 	}
+	defer resp.Body.Close()

 	err = json.NewDecoder(resp.Body).Decode(&keySet)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager.go` around lines 186 - 189, The JSON decode of
resp.Body in manager.go uses json.NewDecoder(resp.Body).Decode(&keySet) but
never closes resp.Body; add a defer resp.Body.Close() immediately after
obtaining and validating resp (before decoding) so the HTTP connection is
released (mirror the pattern used in exchangeCode). Ensure resp.Body.Close() is
deferred even when Decode returns an error.

173-192: ⚠️ Potential issue | 🟠 Major

Inconsistent HTTP client usage: uses http.DefaultClient instead of m.secureClient.

This function uses http.DefaultClient (line 181) to fetch the JWKS, but the exchangeCode function correctly uses m.secureClient for token exchange, and openid.go also properly uses m.secureClient for discovery. This inconsistency could bypass any custom TLS configurations, timeouts, or security policies configured on secureClient.

🔒 Proposed fix to use secureClient consistently
 func (m *Manager) getProviderKeySet(ctx context.Context, oidcConf *zitadeloidc.DiscoveryConfiguration) (*jose.JSONWebKeySet, error) {
 	var keySet jose.JSONWebKeySet
 	uri := oidcConf.JwksURI
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, fmt.Errorf("creating a new HTTP request: %w", err)
 	}

-	resp, err := http.DefaultClient.Do(req)
+	httpClient := m.secureClient
+	if httpClient == nil {
+		httpClient = http.DefaultClient
+	}
+	resp, err := httpClient.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("executing an http request: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager.go` around lines 173 - 192, The getProviderKeySet
function is using http.DefaultClient which bypasses the Manager's configured
m.secureClient; update getProviderKeySet to use m.secureClient for the JWKS HTTP
request and response handling (mirror how exchangeCode and discovery in
openid.go use m.secureClient), ensure the request is created with
http.NewRequestWithContext(ctx, ...) and executed via m.secureClient.Do(req),
and handle/close resp.Body and propagate errors unchanged.
🧹 Nitpick comments (1)
internal/session/openid.go (1)

15-24: Good security enhancement with HTTP scheme validation.

The URL parsing and explicit rejection of insecure http schemes (unless explicitly allowed) is a solid security improvement.

One minor refinement per static analysis: line 23 can use errors.New since there's no format argument.

✨ Optional: Use errors.New for static error message
+import "errors"
+
 func (m *Manager) getOpenIDConfig(ctx context.Context, issuerURL string) (*oidc.DiscoveryConfiguration, error) {
 	...
 	if issuer.Scheme == "http" && !m.allowHttpScheme {
-		return nil, fmt.Errorf("insecure http issuer url is not allowed")
+		return nil, errors.New("insecure http issuer url is not allowed")
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/openid.go` around lines 15 - 24, In getOpenIDConfig, replace
the fmt.Errorf call that returns the static message "insecure http issuer url is
not allowed" with errors.New and ensure the errors package is imported;
specifically update the logic around Manager.allowHttpScheme / issuerURL parsing
in getOpenIDConfig to return errors.New("insecure http issuer url is not
allowed") instead of fmt.Errorf(...) since there are no formatting directives.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/session/manager.go`:
- Around line 186-189: The JSON decode of resp.Body in manager.go uses
json.NewDecoder(resp.Body).Decode(&keySet) but never closes resp.Body; add a
defer resp.Body.Close() immediately after obtaining and validating resp (before
decoding) so the HTTP connection is released (mirror the pattern used in
exchangeCode). Ensure resp.Body.Close() is deferred even when Decode returns an
error.
- Around line 173-192: The getProviderKeySet function is using
http.DefaultClient which bypasses the Manager's configured m.secureClient;
update getProviderKeySet to use m.secureClient for the JWKS HTTP request and
response handling (mirror how exchangeCode and discovery in openid.go use
m.secureClient), ensure the request is created with
http.NewRequestWithContext(ctx, ...) and executed via m.secureClient.Do(req),
and handle/close resp.Body and propagate errors unchanged.

---

Nitpick comments:
In `@internal/session/openid.go`:
- Around line 15-24: In getOpenIDConfig, replace the fmt.Errorf call that
returns the static message "insecure http issuer url is not allowed" with
errors.New and ensure the errors package is imported; specifically update the
logic around Manager.allowHttpScheme / issuerURL parsing in getOpenIDConfig to
return errors.New("insecure http issuer url is not allowed") instead of
fmt.Errorf(...) since there are no formatting directives.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea75819c-e649-4684-9ba2-bb21e7213a5b

📥 Commits

Reviewing files that changed from the base of the PR and between 9c4be99 and 50a4d28.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • go.mod
  • internal/session/manager.go
  • internal/session/openid.go

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/session/manager.go (2)

615-623: ⚠️ Potential issue | 🟠 Major

Add an explicit timeout for token exchange requests.

This is an auth-critical external call; without a deadline it can hang request handling under provider/network issues.

⏱️ Proposed fix
-	req, err := http.NewRequestWithContext(ctx, http.MethodPost, openidConf.TokenEndpoint, strings.NewReader(data.Encode()))
+	reqCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
+	defer cancel()
+	req, err := http.NewRequestWithContext(reqCtx, http.MethodPost, openidConf.TokenEndpoint, strings.NewReader(data.Encode()))
 	if err != nil {
 		return tokenResponse{}, fmt.Errorf("creating request: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager.go` around lines 615 - 623, The token exchange
request can hang because there's no deadline; wrap the request in a cancellable
timeout: create a child context with context.WithTimeout(ctx,
<reasonableDuration>) and defer cancel, use that timed context when building the
request (replace http.NewRequestWithContext(ctx, ...) with the new context) and
then call client.Do(req) as before; alternatively ensure the HTTP client
returned by m.httpClient(mapping) has a non-zero Timeout, but prefer adding
context.WithTimeout around the token exchange to guarantee per-request deadlines
for the code paths around NewRequestWithContext / m.httpClient(mapping) /
client.Do.

165-181: ⚠️ Potential issue | 🟠 Major

Harden JWKS fetch: avoid default client, check status, and close response body.

Current JWKS retrieval can leak connections and may fail in environments needing custom transport settings.

🔧 Proposed fix
-func (m *Manager) getProviderKeySet(ctx context.Context, oidcConf *zitadeloidc.DiscoveryConfiguration) (*jose.JSONWebKeySet, error) {
+func (m *Manager) getProviderKeySet(ctx context.Context, oidcConf *zitadeloidc.DiscoveryConfiguration, mapping trust.OIDCMapping) (*jose.JSONWebKeySet, error) {
 	var keySet jose.JSONWebKeySet
 	uri := oidcConf.JwksURI
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, fmt.Errorf("creating a new HTTP request: %w", err)
 	}

-	resp, err := http.DefaultClient.Do(req)
+	resp, err := m.httpClient(mapping).Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("executing an http request: %w", err)
 	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("fetching jwks failed with status: %d", resp.StatusCode)
+	}

 	err = json.NewDecoder(resp.Body).Decode(&keySet)
 	if err != nil {
 		return nil, fmt.Errorf("decoding keyset response: %w", err)
 	}

Also update call sites in this file:

  • m.getProviderKeySet(ctx, openidConf, mapping) in FinaliseOIDCLogin
  • m.getProviderKeySet(ctx, oidcConf, mapping) in BCLogout
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager.go` around lines 165 - 181, Replace use of
http.DefaultClient and the unclosed response with a safe fetch: create or use a
configurable http.Client (e.g., a client with a timeout or m.httpClient if
available), perform the request with req.Context(), defer resp.Body.Close()
immediately after checking resp != nil, verify resp.StatusCode is 200 (or in
2xx) and return a descriptive error including status and response body when not
OK, and keep decoding into keySet only after those checks; update call sites
FinaliseOIDCLogin and BCLogout to call the revised getProviderKeySet
signature/behavior if you introduce a client dependency or signature change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/session/manager.go`:
- Around line 615-623: The token exchange request can hang because there's no
deadline; wrap the request in a cancellable timeout: create a child context with
context.WithTimeout(ctx, <reasonableDuration>) and defer cancel, use that timed
context when building the request (replace http.NewRequestWithContext(ctx, ...)
with the new context) and then call client.Do(req) as before; alternatively
ensure the HTTP client returned by m.httpClient(mapping) has a non-zero Timeout,
but prefer adding context.WithTimeout around the token exchange to guarantee
per-request deadlines for the code paths around NewRequestWithContext /
m.httpClient(mapping) / client.Do.
- Around line 165-181: Replace use of http.DefaultClient and the unclosed
response with a safe fetch: create or use a configurable http.Client (e.g., a
client with a timeout or m.httpClient if available), perform the request with
req.Context(), defer resp.Body.Close() immediately after checking resp != nil,
verify resp.StatusCode is 200 (or in 2xx) and return a descriptive error
including status and response body when not OK, and keep decoding into keySet
only after those checks; update call sites FinaliseOIDCLogin and BCLogout to
call the revised getProviderKeySet signature/behavior if you introduce a client
dependency or signature change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 23f7be2c-8d3d-4343-91af-72fc789c1be2

📥 Commits

Reviewing files that changed from the base of the PR and between 309e8b9 and b62e663.

📒 Files selected for processing (1)
  • internal/session/manager.go

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/session/openid.go`:
- Around line 22-24: The check that returns a static error when an insecure HTTP
issuer is used (in the block referencing issuer.Scheme and m.allowHttpScheme)
should use errors.New instead of fmt.Errorf; add the errors import to the file
and replace the fmt.Errorf("insecure http issuer url is not allowed") call with
errors.New("insecure http issuer url is not allowed") in the function that
performs the issuer.Scheme check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cbe4f0b0-c1f8-4e80-a9b9-9c3d25747fde

📥 Commits

Reviewing files that changed from the base of the PR and between b62e663 and ea75500.

📒 Files selected for processing (1)
  • internal/session/openid.go

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/session/manager.go (2)

3-31: ⚠️ Potential issue | 🟠 Major

Fix import grouping/formatting to unblock CI.

The quality pipeline is failing on this file (gci) at Line 23. Please run the project’s import formatter (gci/format target) on this file before merge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager.go` around lines 3 - 31, The import block is
misformatted and failing the gci check; run the project's import formatter
(gci/format target) to reorder and group imports correctly in the import block
that contains packages like "context", "github.com/go-jose/go-jose/v4",
"github.com/openkcm/session-manager/internal/config",
"github.com/openkcm/session-manager/internal/credentials" and others so the file
passes CI; ensure standard library, third-party, and internal imports are
grouped per repo style and then commit the changes.

177-195: ⚠️ Potential issue | 🔴 Critical

Handle JWKS HTTP response safely before decoding.

At Line 190, resp.Body is decoded without Close(), and non-200 statuses are not checked. This can leak HTTP connections and mask upstream JWKS errors.

Suggested fix
 func (m *Manager) getProviderKeySet(ctx context.Context, oidcConf *zitadeloidc.DiscoveryConfiguration) (*jose.JSONWebKeySet, error) {
 	var keySet jose.JSONWebKeySet
 	uri := oidcConf.JwksURI
 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, fmt.Errorf("creating a new HTTP request: %w", err)
 	}

 	resp, err := http.DefaultClient.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("executing an http request: %w", err)
 	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("fetching jwks: unexpected status %d", resp.StatusCode)
+	}

 	err = json.NewDecoder(resp.Body).Decode(&keySet)
 	if err != nil {
 		return nil, fmt.Errorf("decoding keyset response: %w", err)
 	}

 	return &keySet, nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/manager.go` around lines 177 - 195, In getProviderKeySet,
ensure the HTTP response is handled safely by deferring resp.Body.Close()
immediately after a successful http.DefaultClient.Do(req) and by checking
resp.StatusCode for non-2xx responses before decoding; for non-OK statuses read
(or io.ReadAll) the body into a string and return a descriptive error (including
status and body) instead of attempting json.Decode on a bad response, then only
json.NewDecoder(resp.Body).Decode(&keySet) for 2xx responses so connections
aren’t leaked and upstream JWKS errors aren’t masked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/session/manager.go`:
- Around line 3-31: The import block is misformatted and failing the gci check;
run the project's import formatter (gci/format target) to reorder and group
imports correctly in the import block that contains packages like "context",
"github.com/go-jose/go-jose/v4",
"github.com/openkcm/session-manager/internal/config",
"github.com/openkcm/session-manager/internal/credentials" and others so the file
passes CI; ensure standard library, third-party, and internal imports are
grouped per repo style and then commit the changes.
- Around line 177-195: In getProviderKeySet, ensure the HTTP response is handled
safely by deferring resp.Body.Close() immediately after a successful
http.DefaultClient.Do(req) and by checking resp.StatusCode for non-2xx responses
before decoding; for non-OK statuses read (or io.ReadAll) the body into a string
and return a descriptive error (including status and body) instead of attempting
json.Decode on a bad response, then only
json.NewDecoder(resp.Body).Decode(&keySet) for 2xx responses so connections
aren’t leaked and upstream JWKS errors aren’t masked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 506173ba-b5cd-43f4-b467-790d99f60948

📥 Commits

Reviewing files that changed from the base of the PR and between ea75500 and c18bfde.

📒 Files selected for processing (1)
  • internal/session/manager.go

@aaishwarya6694 aaishwarya6694 force-pushed the task/implement-zitadel-lib branch from b9d0f71 to c49d727 Compare March 27, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants