OAuth providers
Configure OAuth providers like Discord, Google, and GitHub for single sign-on authentication.
The plugin re-exports 80+ OAuth providers from Auth.js. Import them from @robojs/auth/providers/* and add them to the providers array.
Basic usage
Import providers and configure them with your OAuth credentials:
import Discord from '@robojs/auth/providers/discord'
import Google from '@robojs/auth/providers/google'
import GitHub from '@robojs/auth/providers/github'
import type { AuthPluginOptions } from '@robojs/auth'
export default <AuthPluginOptions>{
secret: process.env.AUTH_SECRET,
providers: [
Discord({ clientId: process.env.DISCORD_CLIENT_ID!, clientSecret: process.env.DISCORD_CLIENT_SECRET! }),
Google({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET! }),
GitHub({ clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET! })
]
}import Discord from '@robojs/auth/providers/discord'
import Google from '@robojs/auth/providers/google'
import GitHub from '@robojs/auth/providers/github'
export default {
secret: process.env.AUTH_SECRET,
providers: [
Discord({ clientId: process.env.DISCORD_CLIENT_ID!, clientSecret: process.env.DISCORD_CLIENT_SECRET! }),
Google({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET! }),
GitHub({ clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET! })
]
}Popular providers
import Discord from '@robojs/auth/providers/discord'
Discord({
clientId: process.env.DISCORD_CLIENT_ID!,
clientSecret: process.env.DISCORD_CLIENT_SECRET!
})import Discord from '@robojs/auth/providers/discord'
Discord({
clientId: process.env.DISCORD_CLIENT_ID!,
clientSecret: process.env.DISCORD_CLIENT_SECRET!
})Callback URL: {AUTH_URL}/api/auth/callback/discord
import Google from '@robojs/auth/providers/google'
Google({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
})import Google from '@robojs/auth/providers/google'
Google({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
})Callback URL: {AUTH_URL}/api/auth/callback/google
import GitHub from '@robojs/auth/providers/github'
GitHub({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!
})import GitHub from '@robojs/auth/providers/github'
GitHub({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!
})Callback URL: {AUTH_URL}/api/auth/callback/github
Callback URLs
Each provider requires a callback URL in the pattern {AUTH_URL}/api/auth/callback/{provider-id}. The AUTH_URL defaults to http://localhost:3000 in development. Register this URL in each provider's developer console.
Available providers
The plugin includes support for Apple, Auth0, Azure AD, Cognito, Discord, Dropbox, Facebook, GitHub, GitLab, Google, Instagram, Keycloak, LinkedIn, Microsoft Entra ID, Notion, Okta, Reddit, Salesforce, Slack, Spotify, Twitch, Twitter, and 60+ more.
Full list at the Auth.js docs. All are imported as @robojs/auth/providers/{name}.
Account linking
Enable allowDangerousEmailAccountLinking to link accounts across providers that share the same email:
export default <AuthPluginOptions>{
allowDangerousEmailAccountLinking: true,
providers: [Discord({ ... }), Google({ ... })]
}export default {
allowDangerousEmailAccountLinking: true,
providers: [Discord({ ... }), Google({ ... })]
}Only enable this if every provider in your config verifies email ownership. Otherwise, an attacker could create an account with a stolen email on one provider and gain access to another user's account.
Combining with email/password
Use OAuth alongside EmailPassword authentication:
import Discord from '@robojs/auth/providers/discord'
import EmailPassword from '@robojs/auth/providers/email-password'
import { createFlashcoreAdapter } from '@robojs/auth'
import type { AuthPluginOptions } from '@robojs/auth'
const adapter = createFlashcoreAdapter({ secret: process.env.AUTH_SECRET! })
export default <AuthPluginOptions>{
secret: process.env.AUTH_SECRET,
adapter,
providers: [
Discord({ clientId: process.env.DISCORD_CLIENT_ID!, clientSecret: process.env.DISCORD_CLIENT_SECRET! }),
EmailPassword({ adapter })
]
}import Discord from '@robojs/auth/providers/discord'
import EmailPassword from '@robojs/auth/providers/email-password'
import { createFlashcoreAdapter } from '@robojs/auth'
const adapter = createFlashcoreAdapter({ secret: process.env.AUTH_SECRET! })
export default {
secret: process.env.AUTH_SECRET,
adapter,
providers: [
Discord({ clientId: process.env.DISCORD_CLIENT_ID!, clientSecret: process.env.DISCORD_CLIENT_SECRET! }),
EmailPassword({ adapter })
]
}Client-side sign-in
Trigger OAuth from the client:
import { signIn } from '@robojs/auth/client'
// Redirect to Discord OAuth
await signIn('discord')
// With callback URL
await signIn('discord', { callbackUrl: '/dashboard' })
// With redirect mode for cross-origin
await signIn('discord', { callbackUrl: '/dashboard' }, { baseUrl: 'https://auth.example.com' }, true)import { signIn } from '@robojs/auth/client'
// Redirect to Discord OAuth
await signIn('discord')
// With callback URL
await signIn('discord', { callbackUrl: '/dashboard' })
// With redirect mode for cross-origin
await signIn('discord', { callbackUrl: '/dashboard' }, { baseUrl: 'https://auth.example.com' }, true)Listing providers at runtime
Retrieve all configured providers on the client:
import { getProviders } from '@robojs/auth/client'
const providers = await getProviders()
// [{ id: 'discord', name: 'Discord', type: 'oauth', ... }, ...]import { getProviders } from '@robojs/auth/client'
const providers = await getProviders()
// [{ id: 'discord', name: 'Discord', type: 'oauth', ... }, ...]Custom callbacks
Extend user data from OAuth providers using callbacks:
export default <AuthPluginOptions>{
providers: [Discord({ ... })],
callbacks: {
async jwt({ token, account, profile }) {
if (account) {
token.accessToken = account.access_token
token.discordId = profile?.id
}
return token
},
async session({ session, token }) {
session.accessToken = token.accessToken
session.discordId = token.discordId
return session
}
}
}export default {
providers: [Discord({ ... })],
callbacks: {
async jwt({ token, account, profile }) {
if (account) {
token.accessToken = account.access_token
token.discordId = profile?.id
}
return token
},
async session({ session, token }) {
session.accessToken = token.accessToken
session.discordId = token.discordId
return session
}
}
}