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 the quickest of the three to set up: no consent screen review, no app modes, no verification. Create an application, add one redirect URL, copy two values.
Quick start
If you already have a client ID and secret, this is the entire integration.
DISCORD_CLIENT_ID=1234567890123456789
DISCORD_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxximport { DiscordSSOApiPlugin } from '@vitnode/core/api/adapters/sso/discord'
import { buildApiConfig } from '@vitnode/core/vitnode.config'
export const vitNodeApiConfig = buildApiConfig({
plugins: [],
authorization: {
ssoAdapters: [
DiscordSSOApiPlugin({
clientId: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
}),
],
},
})Restart the API and a Discord button appears on /login.
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 NEXT_PUBLIC_WEB_URL, so it has to match exactly -
no trailing slash, no locale prefix.
| Environment | Redirect URL |
|---|---|
Development (NEXT_PUBLIC_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.
Invalid OAuth2 redirect_uri
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. Press Reset Secret if the secret was never revealed or you have lost it - Discord shows it once.
Set the environment variables
Server-side variables, so no NEXT_PUBLIC_ prefix - that prefix is what
marks a value for 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=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxRegister the adapter
Add DiscordSSOApiPlugin to authorization.ssoAdapters. It is a plain factory
function, not a class - there is no new.
import { DiscordSSOApiPlugin } from '@vitnode/core/api/adapters/sso/discord'
import { buildApiConfig } from '@vitnode/core/vitnode.config'
export const vitNodeApiConfig = buildApiConfig({
plugins: [],
authorization: {
ssoAdapters: [
DiscordSSOApiPlugin({
clientId: process.env.DISCORD_CLIENT_ID,
clientSecret: process.env.DISCORD_CLIENT_SECRET,
}),
],
},
})The redirect URI is computed when this file is evaluated, so restart the API rather than relying on a hot reload:
bun devpnpm devnpm run devVerify it works
Ask the API what it thinks it supports:
curl http://localhost:3000/api/@vitnode/core/middleware
# {"isEmail":false,"sso":[{"id":"discord","name":"Discord"}]}Then open /login and press Discord. 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, username |
Both scopes are required: identify for the id and username, email for the
address the account is created with.
Gotchas
An account with no email cannot sign in
The adapter requires email in Discord's profile response and answers 400
when it is absent - which is what happens if the email scope is dropped, or
if the Discord account genuinely has no address on it. The visitor sees the
generic error screen.
Discord's email verification flag is not checked
Unlike the Google adapter, which rejects an unverified address, this one takes
Discord's email at face value and never reads Discord's verified field. If
you need that guarantee, copy the adapter into your own project and add the
check - see Custom adapter.
A missing key fails on click, not on boot
A DiscordSSOApiPlugin whose clientId is undefined registers happily -
the button renders and the provider is listed - and 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.
Next
Add Google sign-in to VitNode - create an OAuth client, set the exact redirect URI and register the Google SSO adapter in your API config.
Add Facebook sign-in to VitNode - create a Meta app with the Facebook Login use case, set the OAuth redirect URI and register the Facebook SSO adapter.