Techblah - Using Tailscale with Cognito on your own domain (for free!)
I have been wanting to try Tailscale for a while now, but their somewhat unique decision to require you to host your own OIDC (and deal with security and uptime there … yech) or tie your account to a 3rd party OIDC provider like Github (… yech) presents a real hurdle. I appreciate the security aspects of that decision, and I very much respect their willingness to stick by it. But it still meant that I didn’t get around to trying it for many months.
After the xz security fiasco I decided that I was no longer comfortable with leaving SSH publicly exposed, so it was time to pursue Tailscale in earnest. I didn’t want to spend money on a tech solution that I don’t actually need since I’m my only customer / the only user on my systems, so I was fairly insistent that I would spend zero dollars on this.
In short, the only totally free provider that I could find was Auth0, and their free solution did not include 2FA / one-time passwords (TOTP). To me that represented a downgrade in security which I was uncomfortable with.
But, I was surprised to find that the pricing for AWS Cognito is 100% free if you have < 10,000 users. And while it is technically not a complete OIDC solution, it supports enough of what Tailscale needs, and it has TOTP.
Prereqs
I assume that you have:
- Your own domain
- Email hosted at that domain
- A website hosted at the root of that domain.
If you prefer, I also created a terraform repo for this blog post which will perform steps 1-3 for you. If you use that, then the temporary password will be auto-generated and emailed to you.
1) Create the user pool
If you’ve never worked with identity providers, there’s a lot of lingo involved because these systems are designed to inter-operate in lots of different ways. For our purposes, we need to create a “user pool”, which is like a database that will store all the users of our system.
- Once you’ve logged into the AWS Console and navigated to Cognito, click on User Pools in the left nav menu and Create Pool.
- You will be creating an “app” on this screen at the same time that you create this pool. (A “pool” can have many “apps”.) Name the app “Tailscale”.
- Select email as the username option and also make email required.
- Finally, fill in the Tailscale return URL per their docs. (
https://login.tailscale.com/a/oauth_response)

- After you click Create, you’ll be taken to a screen showing some sample code. You won’t need any of this, so just click “Go to overview”.
- From this screen, copy the “User pool ID”, as you’ll need this later.
2) Create your user
- In the “Overview” for your pool, click “Users” on the left nav.
- Create a user matching the email address that you will sign up for Tailscale with. You don’t need to send yourself an invite email, but you do need to assign a temporary password. Save this password, as you’ll need it in a moment.
3) Enable the OIDC “profile” scope
- From the “App clients” view, click on the “Login pages” section header. You should see a small section labeled “OpenID Connect scopes”, and “profile” probably isn’t listed.
- Click Edit. Disable the “Phone” scope if it’s there, and enable “Profile” scope.

4) Log into Cognito with your pool user
- From the “App clients” view (or terraform output if you went that route), copy the URL from the “View login page” link in the upper-right. You’ll need this in a moment.
- Now Click “View login page”. This should take you to a login where you can use the email address and temporary password from step 2 to log in.
- After you’ve successfully logged in, you’ll be prompted to change your temporary password to a real one. You can also set up your TOTP token here.
- Once you proceed you will find yourself sitting at a Tailscale error page, because Tailscale doesn’t know who you are yet. That’s ok, we have a few more steps to complete before we can sign up.
5) Copy your client secret
- From the “App clients” view (or terraform output), click Show client secret and copy the client secret.
6) Create your webfinger
Webfinger is a way for providers like Tailscale to look at your email address (say, [email protected]) and ask the website associated with that email address (example.com) how to find the correct authentication provider for users coming from that domain, e.g. Cognito in our case. It’s a solid security measure for large companies, but it is slightly annoying for us small folk.
In short, Tailscale will do something like curl https://example.com/.well-known/webfinger?resource=acct%3Ajoe%40example.com. You need to respond with some JSON explaining how to authenticate [email protected]. (Note: the mime-type of the response doesn’t matter.)
Now, if you’re like me and hosting a static site, this is a problem, because you have no way to provide a response that is specific to [email protected]. But if you’re also like me and going to be the only user logging into your Tailscale account, you can just hardcode a static response:
- Create
example.com/.well-known/webfinger:
{
"subject": "acct:[email protected]",
"links": [
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "paste the login URL from step 4 here"
}
]
}7) Create your “openid-configuration”
This works just like Step 6 - Tailscale is going to curl https://example.com/.well-known/openid-configuration. However this time it’s not looking for per-user data, so you can actually hardcode this without guilt / tech debt.
The contents of this file are much more verbose, but fortunately you can get this directly from Cognito. You first need to craft a URL that you are going to curl. If you used terraform, this URL is available in the output.
The format for the URL is:
https://cognito-idp.{AWS region of your user pool}.amazonaws.com/{User pool ID}/.well-known/openid-configurationFor example:
https://cognito-idp.us-east-2.amazonaws.com/us-east-2_abcd12345/.well-known/openid-configurationcurl theUrl > openid-configuration- Upload this file to your website as .well-known/openid-configuration.
Fin!
You’re finally ready to sign up for Tailscale! Just select “Sign in with OIDC” and sign up with the email address for your Cognito user. You’ll have to provide the client secret from step 5.
You can also now use Cognito for any other solution that supports OIDC, which is thankfully a growing number of self-hosted tools. And you’re not on the hook for keeping this alive! Just don’t forget about that webfinger tech debt if/when you finally convince your family to use some of the tools you’re running!
Special thanks
When I originally set this up, the OIDC portions of Cognito were totally undocumented. Now they finally have reasonable defaults, but this Stack Overflow was crucial: https://stackoverflow.com/questions/47664727/can-i-use-aws-cognito-to-provide-a-open-id-connect-endpoint