SSO
Discord
Add Discord sign-in to VitNode. Create an application, register the redirect URL and wire up the Discord SSO adapter in your API config.
Discord is one of the quickest providers to set up, because nothing waits on a review or a publish step. Create an application, add one redirect URL and copy two values.
Before you begin
- A running VitNode app. This page covers only the Discord parts; SSO setup explains the shared steps and where the API's
.envand config live.
Set up the application
Sign in to the Discord Developer Portal
Go to the Discord Developer Portal and sign in with the Discord account that should own the application.
Create a new application
Press New Application, give it the name visitors will see on the authorization screen, and accept the terms.
Add the redirect URL
Open OAuth2 in the left navigation and, under Redirects, press Add Redirect. Paste the URI for the origin you are running and save.
VitNode builds this URI from VITNODE_WEB_URL, so it has to match exactly,
with no trailing slash and no locale prefix.
| Environment | Redirect URL |
|---|---|
Development (VITNODE_WEB_URL unset) | http://localhost:3000/login/sso/discord |
| Production | https://your-domain.com/login/sso/discord |
Add both entries so one application covers local development and your live site.
Discord rejects the authorization request outright if the URL is not in this list, before the visitor sees anything. If pressing the button lands you on a Discord error page rather than an authorization prompt, this is why.
Copy the client ID and secret
Still on the OAuth2 page, the Client ID and Client Secret are in the client information block at the top. Discord shows the secret once, so press Reset Secret if it was never revealed or you have lost it.
Set the environment variables
These are server-side variables, so leave them out of clientEnv. That list
publishes a value to the browser bundle, and a client secret in the browser
bundle is a client secret you have published.
DISCORD_CLIENT_ID=1234567890123456789
DISCORD_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAdd the adapter
Add DiscordSSOApiPlugin to authorization.ssoAdapters in the API's vitnode.api.config.ts (where it lives), next to any adapters you already have. Keep the rest of the config as it is:
import { DiscordSSOApiPlugin } from '@vitnode/core/api/adapters/sso/discord'
import { buildApiConfig } from '@vitnode/core/vitnode.config'
export const vitNodeApiConfig = buildApiConfig({
// ...
authorization: {
ssoAdapters: [
// ...
DiscordSSOApiPlugin({
clientId: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
}),
],
},
})No authorization block yet? Create one with just ssoAdapters, as in the SSO setup. Then restart the dev server, since .env and the API config are only read at start-up.
Check the result
Open /login in a private window and press the Discord button under Continue with. You should see Discord's "connect to"
authorization prompt listing your username and email, get bounced back to
/login/sso/discord?code=...&state=..., and land on the front page signed in.
What the adapter asks Discord for
Useful when you are debugging an authorization prompt that lists the wrong permissions.
| Setting | Value |
|---|---|
| Authorize URL | https://discord.com/oauth2/authorize |
| Token URL | https://discord.com/api/oauth2/token |
| Profile URL | https://discord.com/api/users/@me |
| Scopes | identify email |
| Provider id | discord |
| Fields read | id, email, verified, username, avatar |
Both scopes are required: identify for the id and username, email for the
address the account is created with.
The avatar hash becomes
https://cdn.discordapp.com/avatars/{id}/{avatar}.png?size=512, which
Connected accounts can import. A member
still on Discord's default avatar has none. Discord has no first or last name,
and VitNode doesn't guess one from username or global_name, so only the
avatar is offered.
Gotchas
The adapter requires email in Discord's profile response and answers 400
when it is absent. That happens if the email scope is dropped, or if the
Discord account has no address on it. The visitor sees the
generic error screen.
The adapter reads Discord's verified field and answers 400 when it is
false, so a Discord account with an unconfirmed address cannot sign in until
it confirms the address in Discord. The visitor sees the generic error screen.
A DiscordSSOApiPlugin whose clientId is undefined registers happily.
The button renders, the provider is listed, and it throws Missing Discord client ID the moment somebody presses it. A button that only raises an error
toast is an environment problem, not a portal problem.