Skip to content

feat!: support oauth client for the authkey#89

Merged
gberenice merged 6 commits intomasterpointio:mainfrom
doublethink13:oauth-client-support
Mar 2, 2026
Merged

feat!: support oauth client for the authkey#89
gberenice merged 6 commits intomasterpointio:mainfrom
doublethink13:oauth-client-support

Conversation

@doublethink13
Copy link
Copy Markdown
Contributor

@doublethink13 doublethink13 commented Feb 21, 2026

what

  • Allowing the use of both OAuth client keys and API tokens when running the tailscale up command

why

  • OAuth keys are long lived and their permissions scoped, which makes them easier to manage

references

Closes #86

Summary by CodeRabbit

Release Notes

  • New Features

    • Added OAuth client authentication option for Tailscale connections
    • Consolidated authentication configuration into a single unified interface
  • Changes

    • Individual authentication parameters are now configured through a single authkey_config block
    • Authentication now attempts OAuth client first, then falls back to tailnet key

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

This pull request introduces support for Tailscale OAuth clients as an authentication mechanism alongside existing tailnet keys. The change consolidates four individual authentication-related variables (ephemeral, expiry, preauthorized, reusable) into a single authkey_config object that supports two mutually exclusive configuration methods. The authentication key resolution logic is updated to prioritize OAuth client keys and fall back to tailnet keys. New Terraform resources are conditionally created based on the provided configuration, and validation rules ensure only one authentication method is configured at a time.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested Reviewers

  • oycyc
  • Gowiem
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR successfully implements tailscale_oauth_client support [#86], including resource creation, configuration options, and fallback logic to existing tailnet keys.
Out of Scope Changes check ✅ Passed All changes directly support OAuth client implementation and the refactored authkey_config variable; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately reflects the main change: adding OAuth client support for authentication keys, which is the core objective across all modified files.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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
Contributor

@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

Caution

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

⚠️ Outside diff range comments (1)
README.md (1)

44-57: ⚠️ Potential issue | 🟡 Minor

README example uses removed variable ephemeral — will confuse users and fail on apply.

The ephemeral variable was removed in this PR and replaced by authkey_config. The example on line 56 still passes ephemeral = true, which will produce an "unsupported argument" error for anyone copying this snippet. Please update the example to use authkey_config, showing both OAuth client and tailnet key variants.

📝 Suggested example update (tailnet key path, matching old defaults + ephemeral)
   advertise_routes = [module.vpc.vpc_cidr_block]

-  ephemeral = true
+  authkey_config = {
+    tailscale_tailnet_key = {
+      ephemeral     = true
+      expiry        = 7776000
+      preauthorized = true
+      reusable      = true
+    }
+  }
 }

Consider adding a second example block (or a comment) showing the OAuth client usage as well, since that's the main feature of this PR.

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

In `@README.md` around lines 44 - 57, The README snippet still uses the removed
variable ephemeral; update the example for module "tailscale" to replace
ephemeral with the new authkey_config form and include two sample variants: one
showing the tailnet key variant (equivalent to the old ephemeral behavior) and
another showing the OAuth client variant; specifically, remove ephemeral = true,
add an authkey_config block (e.g. with key = "<TAILNET_KEY>" or with
oauth_client = { client_id = "...", client_secret = "...", redirect_uri = "..."
} or similar fields used by the module) and include brief comments to indicate
which block is which so users can copy the correct variant.
🧹 Nitpick comments (2)
variables.tf (2)

242-256: First validation block is redundant — the XOR check already implies "at least one".

The second validation (lines 250-256) enforces exactly one of the two keys being non-null, which is a strict superset of the "at least one" check (lines 242-248). You can safely drop the first block. If you prefer keeping both for clearer error messages on different failure modes, that's fine too, but be aware the first can never trigger independently once the second exists.

♻️ Simplified to a single validation
-  validation {
-    condition = (
-      var.authkey_config.tailscale_oauth_client != null || 
-      var.authkey_config.tailscale_tailnet_key != null
-    )
-    error_message = "At least one of 'tailscale_oauth_client' or 'tailscale_tailnet_key' must be defined in authkey_config."
-  }
-
   validation {
     condition = (
       var.authkey_config.tailscale_oauth_client == null && var.authkey_config.tailscale_tailnet_key != null || 
       var.authkey_config.tailscale_oauth_client != null && var.authkey_config.tailscale_tailnet_key == null
     )
-    error_message = "Only one of 'tailscale_oauth_client' or 'tailscale_tailnet_key' must be defined in authkey_config."
+    error_message = "Exactly one of 'tailscale_oauth_client' or 'tailscale_tailnet_key' must be defined in authkey_config."
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@variables.tf` around lines 242 - 256, The first validation block checking
var.authkey_config.tailscale_oauth_client != null ||
var.authkey_config.tailscale_tailnet_key != null is redundant because the second
validation enforces an XOR (exactly one) and therefore already guarantees "at
least one"; remove the first validation block (the one whose condition uses ||
and the error_message "At least one of 'tailscale_oauth_client' or
'tailscale_tailnet_key' must be defined in authkey_config.") so only the XOR
validation remains, or if you prefer two messages keep both but ensure you don't
duplicate logic—use the XOR validation in the block that references
var.authkey_config.tailscale_oauth_client == null &&
var.authkey_config.tailscale_tailnet_key != null ||
var.authkey_config.tailscale_oauth_client != null &&
var.authkey_config.tailscale_tailnet_key == null to enforce exclusivity.

206-212: Inconsistent syntax in the default value — mix of : and =.

Line 208 uses : while line 211 uses =. Both are valid HCL, but mixing them in the same block is visually inconsistent and can confuse contributors.

🧹 Proposed fix to unify syntax
   default = {
     "tailscale_tailnet_key" = {
-      "ephemeral": false,
-      "expiry": 7776000,
-      "preauthorized": true,
-      "reusable" = true,
+      "ephemeral"     = false
+      "expiry"        = 7776000
+      "preauthorized" = true
+      "reusable"      = true
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@variables.tf` around lines 206 - 212, The default map for the
"tailscale_tailnet_key" entry mixes HCL syntaxes (colon and equals); update the
block so all attribute assignments use a single syntax style (e.g., change
"ephemeral:", "expiry:", and "preauthorized:" to use "=" to match "reusable" or
vice versa) within the default map for the tailscale_tailnet_key to make the
declaration consistent and readable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@main.tf`:
- Around line 18-21: The current authkey expression uses
try(one(tailscale_oauth_client.default[*].key),
one(tailscale_tailnet_key.default[*].key)) but try() returns the first value
even if it's null so the fallback never runs; modify the expression to use
coalesce for fallback semantics and keep try() as a safety net—i.e., call
coalesce(one(tailscale_oauth_client.default[*].key),
one(tailscale_tailnet_key.default[*].key)) inside try() so authkey resolves to
the first non-null key.

---

Outside diff comments:
In `@README.md`:
- Around line 44-57: The README snippet still uses the removed variable
ephemeral; update the example for module "tailscale" to replace ephemeral with
the new authkey_config form and include two sample variants: one showing the
tailnet key variant (equivalent to the old ephemeral behavior) and another
showing the OAuth client variant; specifically, remove ephemeral = true, add an
authkey_config block (e.g. with key = "<TAILNET_KEY>" or with oauth_client = {
client_id = "...", client_secret = "...", redirect_uri = "..." } or similar
fields used by the module) and include brief comments to indicate which block is
which so users can copy the correct variant.

---

Nitpick comments:
In `@variables.tf`:
- Around line 242-256: The first validation block checking
var.authkey_config.tailscale_oauth_client != null ||
var.authkey_config.tailscale_tailnet_key != null is redundant because the second
validation enforces an XOR (exactly one) and therefore already guarantees "at
least one"; remove the first validation block (the one whose condition uses ||
and the error_message "At least one of 'tailscale_oauth_client' or
'tailscale_tailnet_key' must be defined in authkey_config.") so only the XOR
validation remains, or if you prefer two messages keep both but ensure you don't
duplicate logic—use the XOR validation in the block that references
var.authkey_config.tailscale_oauth_client == null &&
var.authkey_config.tailscale_tailnet_key != null ||
var.authkey_config.tailscale_oauth_client != null &&
var.authkey_config.tailscale_tailnet_key == null to enforce exclusivity.
- Around line 206-212: The default map for the "tailscale_tailnet_key" entry
mixes HCL syntaxes (colon and equals); update the block so all attribute
assignments use a single syntax style (e.g., change "ephemeral:", "expiry:", and
"preauthorized:" to use "=" to match "reusable" or vice versa) within the
default map for the tailscale_tailnet_key to make the declaration consistent and
readable.

doublethink13 and others added 2 commits February 21, 2026 12:45
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@gberenice
Copy link
Copy Markdown
Member

@doublethink13 please bump the Tailscale provider version constraint to 0.20.0 (first version with tailscale_oauth_client).
Also, mind address the remaining coderabbit suggestion regarding the validation? Looks reasonable to me.

@doublethink13
Copy link
Copy Markdown
Contributor Author

@doublethink13 please bump the Tailscale provider version constraint to 0.20.0 (first version with tailscale_oauth_client).

done

Also, mind address the remaining coderabbit suggestion regarding the validation? Looks reasonable to me.

you mean CodeRabbit nitpick comments? i've already addressed both of them 🙂 unless i'm missing something

@gberenice
Copy link
Copy Markdown
Member

you mean CodeRabbit nitpick comments? i've already addressed both of them 🙂 unless i'm missing something

Ah, I might have been reviewing the old version.

@doublethink13 thank you for your contribution! 🫶

@gberenice gberenice added the major label Mar 2, 2026
@gberenice gberenice changed the title feat: support oauth client for the authkey feat!: support oauth client for the authkey Mar 2, 2026
@gberenice gberenice merged commit 8c015d5 into masterpointio:main Mar 2, 2026
5 checks passed
@doublethink13
Copy link
Copy Markdown
Contributor Author

you mean CodeRabbit nitpick comments? i've already addressed both of them 🙂 unless i'm missing something

Ah, I might have been reviewing the old version.

@doublethink13 thank you for your contribution! 🫶

happy to help!

seems like an error reached main, this pr should fix it, but im not really sure why the tests are failing 😅

#92

gberenice added a commit that referenced this pull request Mar 3, 2026
## what

Fixing missing attribute in a variable default

Fixing errors introduced in #89 


#89 (comment)

@gberenice can i have your review here please?


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated default configuration metadata for Subnet Router settings.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Veronika Gnilitska <veronika.gnilitska@gmail.com>
Co-authored-by: Veronika Gnilitska <30597968+gberenice@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support tailscale_oauth_client

2 participants