mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-09-11 07:16:09 +03:00
Add support for auth with Discord (#2110)
This commit is contained in:
parent
5f63b151cf
commit
3b70f90234
@ -19,6 +19,7 @@
|
||||
},
|
||||
}
|
||||
```
|
||||
- Auth: you can now use Discord as a social auth provider (by @wardbox)
|
||||
|
||||
### ⚠️ Breaking Changes & Migration Guide
|
||||
|
||||
|
@ -179,6 +179,9 @@ studio = do
|
||||
[ [ "usernameAndPassword"
|
||||
| isJust $ AS.App.Auth.usernameAndPassword methods
|
||||
],
|
||||
[ "discord"
|
||||
| isJust $ AS.App.Auth.discord methods
|
||||
],
|
||||
[ "google"
|
||||
| isJust $ AS.App.Auth.google methods
|
||||
],
|
||||
|
@ -105,6 +105,9 @@ const SocialAuthButtons = styled('div', {
|
||||
}
|
||||
})
|
||||
{=/ isSocialAuthEnabled =}
|
||||
{=# enabledProviders.isDiscordAuthEnabled =}
|
||||
const discordSignInUrl = `${config.apiUrl}{= discordSignInPath =}`
|
||||
{=/ enabledProviders.isDiscordAuthEnabled =}
|
||||
{=# enabledProviders.isGoogleAuthEnabled =}
|
||||
const googleSignInUrl = `${config.apiUrl}{= googleSignInPath =}`
|
||||
{=/ enabledProviders.isGoogleAuthEnabled =}
|
||||
@ -191,6 +194,9 @@ export const LoginSignupForm = ({
|
||||
<SocialAuth>
|
||||
<SocialAuthLabel>{cta} with</SocialAuthLabel>
|
||||
<SocialAuthButtons gap='large' direction={socialButtonsDirection}>
|
||||
{=# enabledProviders.isDiscordAuthEnabled =}
|
||||
<SocialButton href={discordSignInUrl}><SocialIcons.Discord/></SocialButton>
|
||||
{=/ enabledProviders.isDiscordAuthEnabled =}
|
||||
{=# enabledProviders.isGoogleAuthEnabled =}
|
||||
<SocialButton href={googleSignInUrl}><SocialIcons.Google/></SocialButton>
|
||||
{=/ enabledProviders.isGoogleAuthEnabled =}
|
||||
|
@ -54,3 +54,14 @@ export const GitHub = () => (
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const Discord = () => (
|
||||
<svg
|
||||
className={defaultStyles()}
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M13.545 2.907a13.227 13.227 0 00-3.257-1.011.05.05 0 00-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 00-3.658 0 8.258 8.258 0 00-.412-.833.051.051 0 00-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 00-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 003.995 2.02.05.05 0 00.056-.019c.308-.42.582-.863.818-1.329a.05.05 0 00-.01-.059.051.051 0 00-.018-.011 8.875 8.875 0 01-1.248-.595.05.05 0 01-.02-.066.051.051 0 01.015-.019c.084-.063.168-.129.248-.195a.05.05 0 01.051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 01.053.007c.08.066.164.132.248.195a.051.051 0 01-.004.085 8.254 8.254 0 01-1.249.594.05.05 0 00-.03.03.052.052 0 00.003.041c.24.465.515.909.817 1.329a.05.05 0 00.056.019 13.235 13.235 0 004.001-2.02.049.049 0 00.021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 00-.02-.019zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612z" />
|
||||
</svg>
|
||||
)
|
||||
|
@ -40,6 +40,7 @@ export type OAuthProviderData = {}
|
||||
export type PossibleProviderData = {
|
||||
email: EmailProviderData;
|
||||
username: UsernameProviderData;
|
||||
discord: OAuthProviderData;
|
||||
google: OAuthProviderData;
|
||||
keycloak: OAuthProviderData;
|
||||
github: OAuthProviderData;
|
||||
|
@ -0,0 +1,2 @@
|
||||
// PUBLIC API
|
||||
export { signInUrl as discordSignInUrl } from '../../auth/helpers/Discord'
|
@ -6,6 +6,9 @@ export * from './email'
|
||||
{=# isUsernameAndPasswordAuthEnabled =}
|
||||
export * from './username'
|
||||
{=/ isUsernameAndPasswordAuthEnabled =}
|
||||
{=# isDiscordAuthEnabled =}
|
||||
export * from './discord'
|
||||
{=/ isDiscordAuthEnabled =}
|
||||
{=# isGoogleAuthEnabled =}
|
||||
export * from './google'
|
||||
{=/ isGoogleAuthEnabled =}
|
||||
|
@ -8,6 +8,9 @@ export { VerifyEmailForm } from '../../auth/forms/VerifyEmail'
|
||||
export { ResetPasswordForm } from '../../auth/forms/ResetPassword'
|
||||
{=/ isEmailAuthEnabled =}
|
||||
export type { CustomizationOptions } from '../../auth/forms/types'
|
||||
{=# isDiscordAuthEnabled =}
|
||||
export { SignInButton as DiscordSignInButton } from '../../auth/helpers/Discord'
|
||||
{=/ isDiscordAuthEnabled =}
|
||||
{=# isGoogleAuthEnabled =}
|
||||
export { SignInButton as GoogleSignInButton } from '../../auth/helpers/Google'
|
||||
{=/ isGoogleAuthEnabled =}
|
||||
|
@ -37,6 +37,9 @@ export type AuthUserData = Omit<CompleteUserEntityWithAuth, '{= authFieldOnUserE
|
||||
{=# enabledProviders.isUsernameAndPasswordAuthEnabled =}
|
||||
username: Expand<UserFacingProviderData<'username'>> | null
|
||||
{=/ enabledProviders.isUsernameAndPasswordAuthEnabled =}
|
||||
{=# enabledProviders.isDiscordAuthEnabled =}
|
||||
discord: Expand<UserFacingProviderData<'discord'>> | null
|
||||
{=/ enabledProviders.isDiscordAuthEnabled =}
|
||||
{=# enabledProviders.isGoogleAuthEnabled =}
|
||||
google: Expand<UserFacingProviderData<'google'>> | null
|
||||
{=/ enabledProviders.isGoogleAuthEnabled =}
|
||||
@ -96,6 +99,9 @@ This should never happen, but it did which means there is a bug in the code.`)
|
||||
{=# enabledProviders.isUsernameAndPasswordAuthEnabled =}
|
||||
username: getProviderInfo<'username'>({= authFieldOnUserEntityName =}, 'username'),
|
||||
{=/ enabledProviders.isUsernameAndPasswordAuthEnabled =}
|
||||
{=# enabledProviders.isDiscordAuthEnabled =}
|
||||
discord: getProviderInfo<'discord'>({= authFieldOnUserEntityName =}, 'discord'),
|
||||
{=/ enabledProviders.isDiscordAuthEnabled =}
|
||||
{=# enabledProviders.isGoogleAuthEnabled =}
|
||||
google: getProviderInfo<'google'>({= authFieldOnUserEntityName =}, 'google'),
|
||||
{=/ enabledProviders.isGoogleAuthEnabled =}
|
||||
|
@ -0,0 +1,82 @@
|
||||
{{={= =}=}}
|
||||
import { Discord } from "arctic";
|
||||
|
||||
import type { ProviderConfig } from "wasp/auth/providers/types";
|
||||
import { getRedirectUriForCallback } from "../oauth/redirect.js";
|
||||
import { ensureEnvVarsForProvider } from "../oauth/env.js";
|
||||
import { mergeDefaultAndUserConfig } from "../oauth/config.js";
|
||||
import { createOAuthProviderRouter } from "../oauth/handler.js";
|
||||
|
||||
{=# userSignupFields.isDefined =}
|
||||
{=& userSignupFields.importStatement =}
|
||||
const _waspUserSignupFields = {= userSignupFields.importIdentifier =}
|
||||
{=/ userSignupFields.isDefined =}
|
||||
{=^ userSignupFields.isDefined =}
|
||||
const _waspUserSignupFields = undefined
|
||||
{=/ userSignupFields.isDefined =}
|
||||
{=# configFn.isDefined =}
|
||||
{=& configFn.importStatement =}
|
||||
const _waspUserDefinedConfigFn = {= configFn.importIdentifier =}
|
||||
{=/ configFn.isDefined =}
|
||||
{=^ configFn.isDefined =}
|
||||
const _waspUserDefinedConfigFn = undefined
|
||||
{=/ configFn.isDefined =}
|
||||
|
||||
const _waspConfig: ProviderConfig = {
|
||||
id: "{= providerId =}",
|
||||
displayName: "{= displayName =}",
|
||||
createRouter(provider) {
|
||||
const env = ensureEnvVarsForProvider(
|
||||
["DISCORD_CLIENT_ID", "DISCORD_CLIENT_SECRET"],
|
||||
provider
|
||||
);
|
||||
|
||||
const discord = new Discord(
|
||||
env.DISCORD_CLIENT_ID,
|
||||
env.DISCORD_CLIENT_SECRET,
|
||||
getRedirectUriForCallback(provider.id).toString(),
|
||||
);
|
||||
|
||||
const config = mergeDefaultAndUserConfig({
|
||||
scopes: {=& requiredScopes =},
|
||||
}, _waspUserDefinedConfigFn);
|
||||
|
||||
async function getDiscordProfile(accessToken: string): Promise<{
|
||||
providerProfile: unknown;
|
||||
providerUserId: string;
|
||||
}> {
|
||||
const response = await fetch("https://discord.com/api/users/@me", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
const providerProfile = (await response.json()) as {
|
||||
id?: string;
|
||||
email?: string;
|
||||
global_name?: string;
|
||||
avatar?: string;
|
||||
};
|
||||
|
||||
if (!providerProfile.id) {
|
||||
throw new Error("Invalid profile");
|
||||
}
|
||||
|
||||
if (providerProfile.avatar) {
|
||||
providerProfile.avatar = `https://cdn.discordapp.com/avatars/${providerProfile.id}/${providerProfile.avatar}.png`;
|
||||
}
|
||||
|
||||
return { providerProfile, providerUserId: providerProfile.id };
|
||||
}
|
||||
|
||||
return createOAuthProviderRouter({
|
||||
provider,
|
||||
oAuthType: 'OAuth2',
|
||||
userSignupFields: _waspUserSignupFields,
|
||||
getAuthorizationUrl: ({ state }) => discord.createAuthorizationURL(state, config),
|
||||
getProviderTokens: ({ code }) => discord.validateAuthorizationCode(code),
|
||||
getProviderInfo: ({ accessToken }) => getDiscordProfile(accessToken),
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
export default _waspConfig;
|
@ -67,7 +67,7 @@
|
||||
"file",
|
||||
"../out/sdk/wasp/auth/forms/internal/social/SocialIcons.tsx"
|
||||
],
|
||||
"eb12637809476e963828a91896d260f10552c7dd8d7f48f113ca0bfcee7f9ef0"
|
||||
"0213fcb5830ea8e0ce94d6243c81894d05cceb68199c6ee190eb1b5eba57cabd"
|
||||
],
|
||||
[
|
||||
[
|
||||
@ -165,7 +165,7 @@
|
||||
"file",
|
||||
"../out/sdk/wasp/auth/utils.ts"
|
||||
],
|
||||
"4001e5179622ab1c71646ad4225136a16cb9e7df9890c4bfd767c481e86c7619"
|
||||
"4285ab69fb43af4436b2d8b4f7f330d64036c9ec89a58c29cc700beb2edbb60e"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
@ -54,3 +54,14 @@ export const GitHub = () => (
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export const Discord = () => (
|
||||
<svg
|
||||
className={defaultStyles()}
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path d="M13.545 2.907a13.227 13.227 0 00-3.257-1.011.05.05 0 00-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 00-3.658 0 8.258 8.258 0 00-.412-.833.051.051 0 00-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 00-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 003.995 2.02.05.05 0 00.056-.019c.308-.42.582-.863.818-1.329a.05.05 0 00-.01-.059.051.051 0 00-.018-.011 8.875 8.875 0 01-1.248-.595.05.05 0 01-.02-.066.051.051 0 01.015-.019c.084-.063.168-.129.248-.195a.05.05 0 01.051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 01.053.007c.08.066.164.132.248.195a.051.051 0 01-.004.085 8.254 8.254 0 01-1.249.594.05.05 0 00-.03.03.052.052 0 00.003.041c.24.465.515.909.817 1.329a.05.05 0 00.056.019 13.235 13.235 0 004.001-2.02.049.049 0 00.021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 00-.02-.019zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612z" />
|
||||
</svg>
|
||||
)
|
||||
|
@ -39,6 +39,7 @@ export type OAuthProviderData = {}
|
||||
export type PossibleProviderData = {
|
||||
email: EmailProviderData;
|
||||
username: UsernameProviderData;
|
||||
discord: OAuthProviderData;
|
||||
google: OAuthProviderData;
|
||||
keycloak: OAuthProviderData;
|
||||
github: OAuthProviderData;
|
||||
|
@ -1,3 +1,4 @@
|
||||
export declare const Google: () => import("react").JSX.Element;
|
||||
export declare const Keycloak: () => import("react").JSX.Element;
|
||||
export declare const GitHub: () => import("react").JSX.Element;
|
||||
export declare const Discord: () => import("react").JSX.Element;
|
||||
|
@ -20,4 +20,7 @@ export const Keycloak = () => (<svg className={defaultStyles()} aria-hidden="tru
|
||||
export const GitHub = () => (<svg className={defaultStyles()} aria-hidden="true" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z" clipRule="evenodd"/>
|
||||
</svg>);
|
||||
export const Discord = () => (<svg className={defaultStyles()} aria-hidden="true" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M13.545 2.907a13.227 13.227 0 00-3.257-1.011.05.05 0 00-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 00-3.658 0 8.258 8.258 0 00-.412-.833.051.051 0 00-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 00-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 003.995 2.02.05.05 0 00.056-.019c.308-.42.582-.863.818-1.329a.05.05 0 00-.01-.059.051.051 0 00-.018-.011 8.875 8.875 0 01-1.248-.595.05.05 0 01-.02-.066.051.051 0 01.015-.019c.084-.063.168-.129.248-.195a.05.05 0 01.051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 01.053.007c.08.066.164.132.248.195a.051.051 0 01-.004.085 8.254 8.254 0 01-1.249.594.05.05 0 00-.03.03.052.052 0 00.003.041c.24.465.515.909.817 1.329a.05.05 0 00.056.019 13.235 13.235 0 004.001-2.02.049.049 0 00.021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 00-.02-.019zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612z"/>
|
||||
</svg>);
|
||||
//# sourceMappingURL=SocialIcons.jsx.map
|
@ -1 +1 @@
|
||||
{"version":3,"file":"SocialIcons.jsx","sourceRoot":"","sources":["../../../../../auth/forms/internal/social/SocialIcons.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAErC,MAAM,aAAa,GAAG,GAAG,CAAC;IACxB,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;CAClB,CAAC,CAAA;AAEF,cAAc;AACd,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,CAC1B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,WAAW,CAEnB;IAAA,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CACxE;MAAA,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC9C;QAAA,CAAC,IAAI,CACH,CAAC,CAAC,sVAAsV,CACxV,EAAE,CAAC,OAAO,CACX,EAAE,IAAI,CACT;MAAA,EAAE,CAAC,CACL;IAAA,EAAE,CAAC,CACL;EAAA,EAAE,GAAG,CAAC,CACP,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,CAC5B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,aAAa,CAErB;IAAA,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,iCAAiC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CACzF;MAAA,CAAC,IAAI,CACH,CAAC,CAAC,+iDAA+iD,EAErjD;IAAA,EAAE,CAAC,CACL;EAAA,EAAE,GAAG,CAAC,CACP,CAAA;AAED,cAAc;AACd,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,CAC1B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,WAAW,CAEnB;IAAA,CAAC,IAAI,CACH,QAAQ,CAAC,SAAS,CAClB,CAAC,CAAC,ktBAAktB,CACptB,QAAQ,CAAC,SAAS,EAEtB;EAAA,EAAE,GAAG,CAAC,CACP,CAAA"}
|
||||
{"version":3,"file":"SocialIcons.jsx","sourceRoot":"","sources":["../../../../../auth/forms/internal/social/SocialIcons.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAErC,MAAM,aAAa,GAAG,GAAG,CAAC;IACxB,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;CAClB,CAAC,CAAA;AAEF,cAAc;AACd,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,CAC1B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,WAAW,CAEnB;IAAA,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CACxE;MAAA,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAC9C;QAAA,CAAC,IAAI,CACH,CAAC,CAAC,sVAAsV,CACxV,EAAE,CAAC,OAAO,CACX,EAAE,IAAI,CACT;MAAA,EAAE,CAAC,CACL;IAAA,EAAE,CAAC,CACL;EAAA,EAAE,GAAG,CAAC,CACP,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,CAC5B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,aAAa,CAErB;IAAA,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,iCAAiC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CACzF;MAAA,CAAC,IAAI,CACH,CAAC,CAAC,+iDAA+iD,EAErjD;IAAA,EAAE,CAAC,CACL;EAAA,EAAE,GAAG,CAAC,CACP,CAAA;AAED,cAAc;AACd,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,CAC1B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,WAAW,CAEnB;IAAA,CAAC,IAAI,CACH,QAAQ,CAAC,SAAS,CAClB,CAAC,CAAC,ktBAAktB,CACptB,QAAQ,CAAC,SAAS,EAEtB;EAAA,EAAE,GAAG,CAAC,CACP,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAC3B,CAAC,GAAG,CACF,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAC3B,WAAW,CAAC,MAAM,CAClB,IAAI,CAAC,cAAc,CACnB,OAAO,CAAC,WAAW,CAEnB;IAAA,CAAC,IAAI,CAAC,CAAC,CAAC,0kCAA0kC,EACplC;EAAA,EAAE,GAAG,CAAC,CACP,CAAA"}
|
@ -21,6 +21,7 @@ export type OAuthProviderData = {};
|
||||
export type PossibleProviderData = {
|
||||
email: EmailProviderData;
|
||||
username: UsernameProviderData;
|
||||
discord: OAuthProviderData;
|
||||
google: OAuthProviderData;
|
||||
keycloak: OAuthProviderData;
|
||||
github: OAuthProviderData;
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../auth/utils.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../auth/utils.ts"],"names":[],"mappings":"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"}
|
@ -18,3 +18,7 @@ GITHUB_CLIENT_SECRET='dummy-gh-client-secret'
|
||||
# KEYCLOAK_CLIENT_ID='dummy-id'
|
||||
# KEYCLOAK_CLIENT_SECRET='dummy-secret'
|
||||
# KEYCLOAK_REALM_URL='dummy-url'
|
||||
|
||||
# Dummy values here will allow app to run, but you will need real values to get Discord Auth to work.
|
||||
DISCORD_CLIENT_SECRET='dummy-discord-client-secret'
|
||||
DISCORD_CLIENT_ID='dummy-discord-client-id'
|
||||
|
@ -14,6 +14,10 @@ app todoApp {
|
||||
// usernameAndPassword: {
|
||||
// userSignupFields: import { userSignupFields } from "@src/auth/github",
|
||||
// },
|
||||
discord: {
|
||||
configFn: import { config } from "@src/auth/discord",
|
||||
userSignupFields: import { userSignupFields } from "@src/auth/discord"
|
||||
},
|
||||
google: {
|
||||
configFn: import { config } from "@src/auth/google",
|
||||
userSignupFields: import { userSignupFields } from "@src/auth/google"
|
||||
|
10
waspc/examples/todoApp/src/auth/discord.ts
Normal file
10
waspc/examples/todoApp/src/auth/discord.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { defineUserSignupFields } from 'wasp/server/auth'
|
||||
|
||||
export function config() {
|
||||
console.log('Inside user-supplied Discord config')
|
||||
return {
|
||||
scopes: ['identify', 'email'],
|
||||
}
|
||||
}
|
||||
|
||||
export const userSignupFields = defineUserSignupFields({})
|
@ -1,3 +1,3 @@
|
||||
GOOGLE_CLIENT_ID="mock-client-id"
|
||||
GOOGLE_CLIENT_SECRET="mock-client-secret"
|
||||
SKIP_EMAIL_VERIFICATION_IN_DEV=true
|
||||
SKIP_EMAIL_VERIFICATION_IN_DEV=true
|
||||
|
@ -9,6 +9,7 @@ module Wasp.AppSpec.App.Auth
|
||||
UsernameAndPasswordConfig (..),
|
||||
isUsernameAndPasswordAuthEnabled,
|
||||
isExternalAuthEnabled,
|
||||
isDiscordAuthEnabled,
|
||||
isGoogleAuthEnabled,
|
||||
isKeycloakAuthEnabled,
|
||||
isGitHubAuthEnabled,
|
||||
@ -42,6 +43,7 @@ data Auth = Auth
|
||||
|
||||
data AuthMethods = AuthMethods
|
||||
{ usernameAndPassword :: Maybe UsernameAndPasswordConfig,
|
||||
discord :: Maybe ExternalAuthConfig,
|
||||
google :: Maybe ExternalAuthConfig,
|
||||
gitHub :: Maybe ExternalAuthConfig,
|
||||
keycloak :: Maybe ExternalAuthConfig,
|
||||
@ -76,11 +78,15 @@ isExternalAuthEnabled auth =
|
||||
any
|
||||
($ auth)
|
||||
-- NOTE: Make sure to add new external auth methods here.
|
||||
[ isGoogleAuthEnabled,
|
||||
[ isDiscordAuthEnabled,
|
||||
isGoogleAuthEnabled,
|
||||
isGitHubAuthEnabled,
|
||||
isKeycloakAuthEnabled
|
||||
]
|
||||
|
||||
isDiscordAuthEnabled :: Auth -> Bool
|
||||
isDiscordAuthEnabled = isJust . discord . methods
|
||||
|
||||
isGoogleAuthEnabled :: Auth -> Bool
|
||||
isGoogleAuthEnabled = isJust . google . methods
|
||||
|
||||
|
@ -47,10 +47,19 @@ emailAuthProvider =
|
||||
E._displayName = "Email and password"
|
||||
}
|
||||
|
||||
discordAuthProvider :: OA.OAuthAuthProvider
|
||||
discordAuthProvider =
|
||||
OA.OAuthAuthProvider
|
||||
{ OA._providerId = fromJust $ makeProviderId "discord",
|
||||
OA._displayName = "Discord",
|
||||
OA._requiredScope = ["identify"]
|
||||
}
|
||||
|
||||
getEnabledAuthProvidersJson :: AS.Auth.Auth -> Aeson.Value
|
||||
getEnabledAuthProvidersJson auth =
|
||||
object
|
||||
[ "isGoogleAuthEnabled" .= AS.Auth.isGoogleAuthEnabled auth,
|
||||
[ "isDiscordAuthEnabled" .= AS.Auth.isDiscordAuthEnabled auth,
|
||||
"isGoogleAuthEnabled" .= AS.Auth.isGoogleAuthEnabled auth,
|
||||
"isKeycloakAuthEnabled" .= AS.Auth.isKeycloakAuthEnabled auth,
|
||||
"isGitHubAuthEnabled" .= AS.Auth.isGitHubAuthEnabled auth,
|
||||
"isUsernameAndPasswordAuthEnabled" .= AS.Auth.isUsernameAndPasswordAuthEnabled auth,
|
||||
|
@ -7,7 +7,8 @@ import Data.Aeson (object, (.=))
|
||||
import StrongPath (reldir, relfile, (</>))
|
||||
import qualified Wasp.AppSpec.App.Auth as AS.Auth
|
||||
import Wasp.Generator.AuthProviders
|
||||
( gitHubAuthProvider,
|
||||
( discordAuthProvider,
|
||||
gitHubAuthProvider,
|
||||
googleAuthProvider,
|
||||
keycloakAuthProvider,
|
||||
)
|
||||
@ -119,6 +120,7 @@ genLoginSignupForm auth =
|
||||
"areBothSocialAndPasswordBasedAuthEnabled" .= areBothSocialAndPasswordBasedAuthEnabled,
|
||||
"isAnyPasswordBasedAuthEnabled" .= isAnyPasswordBasedAuthEnabled,
|
||||
"isSocialAuthEnabled" .= AS.Auth.isExternalAuthEnabled auth,
|
||||
"discordSignInPath" .= OAuth.serverLoginUrl discordAuthProvider,
|
||||
"googleSignInPath" .= OAuth.serverLoginUrl googleAuthProvider,
|
||||
"keycloakSignInPath" .= OAuth.serverLoginUrl keycloakAuthProvider,
|
||||
"gitHubSignInPath" .= OAuth.serverLoginUrl gitHubAuthProvider,
|
||||
|
@ -8,7 +8,8 @@ import StrongPath (File', Path', Rel', reldir, relfile)
|
||||
import qualified StrongPath as SP
|
||||
import qualified Wasp.AppSpec.App.Auth as AS.Auth
|
||||
import Wasp.Generator.AuthProviders
|
||||
( gitHubAuthProvider,
|
||||
( discordAuthProvider,
|
||||
gitHubAuthProvider,
|
||||
googleAuthProvider,
|
||||
keycloakAuthProvider,
|
||||
)
|
||||
@ -28,11 +29,13 @@ genHelpers :: AS.Auth.Auth -> Generator [FileDraft]
|
||||
genHelpers auth =
|
||||
return $
|
||||
concat
|
||||
[ [gitHubHelpers | AS.Auth.isGitHubAuthEnabled auth],
|
||||
[ [discordHelpers | AS.Auth.isDiscordAuthEnabled auth],
|
||||
[gitHubHelpers | AS.Auth.isGitHubAuthEnabled auth],
|
||||
[googleHelpers | AS.Auth.isGoogleAuthEnabled auth],
|
||||
[keycloakHelpers | AS.Auth.isKeycloakAuthEnabled auth]
|
||||
]
|
||||
where
|
||||
discordHelpers = mkHelpersFd discordAuthProvider [relfile|Discord.tsx|]
|
||||
gitHubHelpers = mkHelpersFd gitHubAuthProvider [relfile|GitHub.tsx|]
|
||||
googleHelpers = mkHelpersFd googleAuthProvider [relfile|Google.tsx|]
|
||||
keycloakHelpers = mkHelpersFd keycloakAuthProvider [relfile|Keycloak.tsx|]
|
||||
|
@ -26,6 +26,7 @@ genNewClientAuth spec =
|
||||
]
|
||||
<++> genAuthEmail auth
|
||||
<++> genAuthUsername auth
|
||||
<++> genAuthDiscord auth
|
||||
<++> genAuthGoogle auth
|
||||
<++> genAuthKeycloak auth
|
||||
<++> genAuthGitHub auth
|
||||
@ -62,6 +63,12 @@ genAuthUsername auth =
|
||||
then sequence [genFileCopy [relfile|client/auth/username.ts|]]
|
||||
else return []
|
||||
|
||||
genAuthDiscord :: AS.Auth.Auth -> Generator [FileDraft]
|
||||
genAuthDiscord auth =
|
||||
if AS.Auth.isDiscordAuthEnabled auth
|
||||
then sequence [genFileCopy [relfile|client/auth/discord.ts|]]
|
||||
else return []
|
||||
|
||||
genAuthGoogle :: AS.Auth.Auth -> Generator [FileDraft]
|
||||
genAuthGoogle auth =
|
||||
if AS.Auth.isGoogleAuthEnabled auth
|
||||
|
@ -27,7 +27,8 @@ import qualified Wasp.AppSpec.App.Auth as AS.Auth
|
||||
import qualified Wasp.AppSpec.App.Dependency as App.Dependency
|
||||
import Wasp.AppSpec.Valid (getApp)
|
||||
import Wasp.Generator.AuthProviders
|
||||
( gitHubAuthProvider,
|
||||
( discordAuthProvider,
|
||||
gitHubAuthProvider,
|
||||
googleAuthProvider,
|
||||
keycloakAuthProvider,
|
||||
)
|
||||
@ -52,6 +53,7 @@ genOAuthAuth :: AS.Auth.Auth -> Generator [FileDraft]
|
||||
genOAuthAuth auth
|
||||
| AS.Auth.isExternalAuthEnabled auth =
|
||||
genOAuthHelpers auth
|
||||
<++> genOAuthProvider discordAuthProvider (AS.Auth.discord . AS.Auth.methods $ auth)
|
||||
<++> genOAuthProvider googleAuthProvider (AS.Auth.google . AS.Auth.methods $ auth)
|
||||
<++> genOAuthProvider keycloakAuthProvider (AS.Auth.keycloak . AS.Auth.methods $ auth)
|
||||
<++> genOAuthProvider gitHubAuthProvider (AS.Auth.gitHub . AS.Auth.methods $ auth)
|
||||
|
@ -24,7 +24,8 @@ import qualified Wasp.AppSpec.App.Auth as AS.Auth
|
||||
import qualified Wasp.AppSpec.App.Dependency as AS.Dependency
|
||||
import Wasp.AppSpec.Valid (getApp)
|
||||
import Wasp.Generator.AuthProviders
|
||||
( emailAuthProvider,
|
||||
( discordAuthProvider,
|
||||
emailAuthProvider,
|
||||
gitHubAuthProvider,
|
||||
googleAuthProvider,
|
||||
keycloakAuthProvider,
|
||||
@ -85,7 +86,8 @@ genProvidersIndex auth = return $ C.mkTmplFdWithData [relfile|src/auth/providers
|
||||
providers =
|
||||
makeConfigImportJson
|
||||
<$> concat
|
||||
[ [OAuthProvider.providerId gitHubAuthProvider | AS.Auth.isGitHubAuthEnabled auth],
|
||||
[ [OAuthProvider.providerId discordAuthProvider | AS.Auth.isDiscordAuthEnabled auth],
|
||||
[OAuthProvider.providerId gitHubAuthProvider | AS.Auth.isGitHubAuthEnabled auth],
|
||||
[OAuthProvider.providerId googleAuthProvider | AS.Auth.isGoogleAuthEnabled auth],
|
||||
[OAuthProvider.providerId keycloakAuthProvider | AS.Auth.isKeycloakAuthEnabled auth],
|
||||
[LocalProvider.providerId localAuthProvider | AS.Auth.isUsernameAndPasswordAuthEnabled auth],
|
||||
|
@ -143,6 +143,7 @@ spec_Analyzer = do
|
||||
Auth.UsernameAndPasswordConfig
|
||||
{ Auth.userSignupFields = Just $ ExtImport (ExtImportField "getUserFields") (fromJust $ SP.parseRelFileP "auth/signup.js")
|
||||
},
|
||||
Auth.discord = Nothing,
|
||||
Auth.google = Nothing,
|
||||
Auth.keycloak = Nothing,
|
||||
Auth.gitHub = Nothing,
|
||||
|
@ -109,6 +109,7 @@ spec_AppSpecValid = do
|
||||
AS.Auth.methods =
|
||||
AS.Auth.AuthMethods
|
||||
{ AS.Auth.usernameAndPassword = Just AS.Auth.UsernameAndPasswordConfig {AS.Auth.userSignupFields = Nothing},
|
||||
AS.Auth.discord = Nothing,
|
||||
AS.Auth.google = Nothing,
|
||||
AS.Auth.gitHub = Nothing,
|
||||
AS.Auth.keycloak = Nothing,
|
||||
@ -199,7 +200,7 @@ spec_AppSpecValid = do
|
||||
}
|
||||
|
||||
it "returns no error if app.auth is not set" $ do
|
||||
ASV.validateAppSpec (makeSpec (AS.Auth.AuthMethods {usernameAndPassword = Nothing, google = Nothing, keycloak = Nothing, gitHub = Nothing, email = Nothing}) validUserEntity) `shouldBe` []
|
||||
ASV.validateAppSpec (makeSpec (AS.Auth.AuthMethods {usernameAndPassword = Nothing, discord = Nothing, google = Nothing, keycloak = Nothing, gitHub = Nothing, email = Nothing}) validUserEntity) `shouldBe` []
|
||||
|
||||
it "returns no error if app.auth is set and only one of UsernameAndPassword and Email is used" $ do
|
||||
ASV.validateAppSpec
|
||||
@ -210,6 +211,7 @@ spec_AppSpecValid = do
|
||||
AS.Auth.UsernameAndPasswordConfig
|
||||
{ AS.Auth.userSignupFields = Nothing
|
||||
},
|
||||
discord = Nothing,
|
||||
google = Nothing,
|
||||
keycloak = Nothing,
|
||||
gitHub = Nothing,
|
||||
@ -219,7 +221,7 @@ spec_AppSpecValid = do
|
||||
validUserEntity
|
||||
)
|
||||
`shouldBe` []
|
||||
ASV.validateAppSpec (makeSpec (AS.Auth.AuthMethods {usernameAndPassword = Nothing, google = Nothing, keycloak = Nothing, gitHub = Nothing, email = Just emailAuthConfig}) validUserEntity) `shouldBe` []
|
||||
ASV.validateAppSpec (makeSpec (AS.Auth.AuthMethods {usernameAndPassword = Nothing, discord = Nothing, google = Nothing, keycloak = Nothing, gitHub = Nothing, email = Just emailAuthConfig}) validUserEntity) `shouldBe` []
|
||||
|
||||
it "returns an error if app.auth is set and both UsernameAndPassword and Email are used" $ do
|
||||
ASV.validateAppSpec
|
||||
@ -230,6 +232,7 @@ spec_AppSpecValid = do
|
||||
AS.Auth.UsernameAndPasswordConfig
|
||||
{ AS.Auth.userSignupFields = Nothing
|
||||
},
|
||||
discord = Nothing,
|
||||
google = Nothing,
|
||||
keycloak = Nothing,
|
||||
gitHub = Nothing,
|
||||
@ -297,7 +300,7 @@ spec_AppSpecValid = do
|
||||
Just
|
||||
AS.Auth.Auth
|
||||
{ AS.Auth.methods =
|
||||
AS.Auth.AuthMethods {email = Just emailAuthConfig, usernameAndPassword = Nothing, google = Nothing, keycloak = Nothing, gitHub = Nothing},
|
||||
AS.Auth.AuthMethods {email = Just emailAuthConfig, usernameAndPassword = Nothing, discord = Nothing, google = Nothing, keycloak = Nothing, gitHub = Nothing},
|
||||
AS.Auth.userEntity = AS.Core.Ref.Ref userEntityName,
|
||||
AS.Auth.externalAuthEntity = Nothing,
|
||||
AS.Auth.onAuthFailedRedirectTo = "/",
|
||||
|
@ -1,6 +1,7 @@
|
||||
:root {
|
||||
--auth-pills-color: #333;
|
||||
--auth-pills-email: #e0f2fe;
|
||||
--auth-pills-discord: #d3d6f2;
|
||||
--auth-pills-github: #f1f5f9;
|
||||
--auth-pills-google: #ecfccb;
|
||||
--auth-pills-keycloak: #d0ebf5;
|
||||
@ -10,6 +11,7 @@
|
||||
:root[data-theme='dark'] {
|
||||
--auth-pills-color: #fff;
|
||||
--auth-pills-email: #0c4a6e;
|
||||
--auth-pills-discord: #2f3670;
|
||||
--auth-pills-github: #334155;
|
||||
--auth-pills-google: #365314;
|
||||
--auth-pills-keycloak: #2d5866;
|
||||
|
@ -46,6 +46,19 @@ export function UsernameAndPasswordPill() {
|
||||
)
|
||||
}
|
||||
|
||||
export function DiscordPill() {
|
||||
return (
|
||||
<Pill
|
||||
style={{
|
||||
backgroundColor: 'var(--auth-pills-discord)',
|
||||
}}
|
||||
linkToPage="/docs/auth/social-auth/discord"
|
||||
>
|
||||
Discord
|
||||
</Pill>
|
||||
)
|
||||
}
|
||||
|
||||
export function GithubPill() {
|
||||
return (
|
||||
<Pill
|
||||
|
@ -2,7 +2,7 @@
|
||||
title: Auth Hooks
|
||||
---
|
||||
|
||||
import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill, KeycloakPill } from "./Pills";
|
||||
import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill, KeycloakPill, DiscordPill } from "./Pills";
|
||||
import ImgWithCaption from '@site/blog/components/ImgWithCaption'
|
||||
|
||||
Auth hooks allow you to "hook into" the auth process at various stages and run your custom code. For example, if you want to forbid certain emails from signing up, or if you wish to send a welcome email to the user after they sign up, auth hooks are the way to go.
|
||||
@ -87,7 +87,7 @@ Wasp calls the `onBeforeSignup` hook before the user is created.
|
||||
|
||||
The `onBeforeSignup` hook can be useful if you want to reject a user based on some criteria before they sign up.
|
||||
|
||||
Works with <EmailPill /> <UsernameAndPasswordPill /> <GithubPill /> <GooglePill /> <KeycloakPill />
|
||||
Works with <EmailPill /> <UsernameAndPasswordPill /> <DiscordPill /> <GithubPill /> <GooglePill /> <KeycloakPill />
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
@ -175,7 +175,7 @@ The `onAfterSignup` hook can be useful if you want to send the user a welcome em
|
||||
|
||||
Since the `onAfterSignup` hook receives the OAuth access token, it can also be used to store the OAuth access token for the user in your database.
|
||||
|
||||
Works with <EmailPill /> <UsernameAndPasswordPill /> <GithubPill /> <GooglePill /> <KeycloakPill />
|
||||
Works with <EmailPill /> <UsernameAndPasswordPill /> <DiscordPill /> <GithubPill /> <GooglePill /> <KeycloakPill />
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
@ -270,7 +270,7 @@ Wasp calls the `onBeforeOAuthRedirect` hook after the OAuth redirect URL is gene
|
||||
|
||||
The `onBeforeOAuthRedirect` hook can be useful if you want to save some data (e.g. request query parameters) that can be used later in the OAuth flow. You can use the `uniqueRequestId` parameter to reference this data later in the `onAfterSignup` hook.
|
||||
|
||||
Works with <GithubPill /> <GooglePill /> <KeycloakPill />
|
||||
Works with <DiscordPill /> <GithubPill /> <GooglePill /> <KeycloakPill />
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
@ -21,6 +21,11 @@ export function SocialAuthGrid({
|
||||
description: 'Users sign in with their Keycloak account.',
|
||||
linkToDocs: '/docs/auth/social-auth/keycloak' + pagePart,
|
||||
},
|
||||
{
|
||||
title: 'Discord',
|
||||
description: 'Users sign in with their Discord account.',
|
||||
linkToDocs: '/docs/auth/social-auth/discord' + pagePart,
|
||||
},
|
||||
]
|
||||
return (
|
||||
<>
|
||||
|
549
web/docs/auth/social-auth/discord.md
Normal file
549
web/docs/auth/social-auth/discord.md
Normal file
@ -0,0 +1,549 @@
|
||||
---
|
||||
title: Discord
|
||||
---
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import DefaultBehaviour from './\_default-behaviour.md';
|
||||
import OverrideIntro from './\_override-intro.md';
|
||||
import OverrideExampleIntro from './\_override-example-intro.md';
|
||||
import UsingAuthNote from './\_using-auth-note.md';
|
||||
import WaspFileStructureNote from './\_wasp-file-structure-note.md';
|
||||
import GetUserFieldsType from './\_getuserfields-type.md';
|
||||
import ApiReferenceIntro from './\_api-reference-intro.md';
|
||||
import UserSignupFieldsExplainer from '../\_user-signup-fields-explainer.md';
|
||||
|
||||
Wasp supports Discord Authentication out of the box.
|
||||
|
||||
Letting your users log in using their Discord accounts turns the signup process into a breeze.
|
||||
|
||||
Let's walk through enabling Discord Authentication, explain some of the default settings, and show how to override them.
|
||||
|
||||
## Setting up Discord Auth
|
||||
|
||||
Enabling Discord Authentication comes down to a series of steps:
|
||||
|
||||
1. Enabling Discord authentication in the Wasp file.
|
||||
1. Adding the `User` entity.
|
||||
1. Creating a Discord App.
|
||||
1. Adding the necessary Routes and Pages
|
||||
1. Using Auth UI components in our Pages.
|
||||
|
||||
<WaspFileStructureNote />
|
||||
|
||||
### 1. Adding Discord Auth to Your Wasp File
|
||||
|
||||
Let's start by properly configuring the Auth object:
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
// highlight-next-line
|
||||
// 1. Specify the User entity (we'll define it next)
|
||||
// highlight-next-line
|
||||
userEntity: User,
|
||||
methods: {
|
||||
// highlight-next-line
|
||||
// 2. Enable Discord Auth
|
||||
// highlight-next-line
|
||||
discord: {}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
// highlight-next-line
|
||||
// 1. Specify the User entity (we'll define it next)
|
||||
// highlight-next-line
|
||||
userEntity: User,
|
||||
methods: {
|
||||
// highlight-next-line
|
||||
// 2. Enable Discord Auth
|
||||
// highlight-next-line
|
||||
discord: {}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### 2. Add the User Entity
|
||||
|
||||
Let's now define the `app.auth.userEntity` entity:
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
// ...
|
||||
// 3. Define the User entity
|
||||
// highlight-next-line
|
||||
entity User {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
// ...
|
||||
psl=}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
// ...
|
||||
// 3. Define the User entity
|
||||
// highlight-next-line
|
||||
entity User {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
// ...
|
||||
psl=}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### 3. Creating a Discord App
|
||||
|
||||
To use Discord as an authentication method, you'll first need to create a Discord App and provide Wasp with your client key and secret. Here's how you do it:
|
||||
|
||||
1. Log into your Discord account and navigate to: https://discord.com/developers/applications.
|
||||
2. Select **New Application**.
|
||||
3. Supply required information.
|
||||
|
||||
<img alt="Discord Applications Screenshot"
|
||||
src={useBaseUrl('img/integrations-discord-1.png')}
|
||||
width="400px"
|
||||
/>
|
||||
|
||||
4. Go to the **OAuth2** tab on the sidebar and click **Add Redirect**
|
||||
- For development, put: `http://localhost:3001/auth/discord/callback`.
|
||||
- Once you know on which URL your API server will be deployed, you can create a new app with that URL instead e.g. `https://your-server-url.com/auth/discord/callback`.
|
||||
|
||||
4. Hit **Save Changes**.
|
||||
5. Hit **Reset Secret**
|
||||
6. Copy your Client ID and Client secret as you'll need them in the next step.
|
||||
|
||||
### 4. Adding Environment Variables
|
||||
|
||||
Add these environment variables to the `.env.server` file at the root of your project (take their values from the previous step):
|
||||
|
||||
```bash title=".env.server"
|
||||
DISCORD_CLIENT_ID=your-discord-client-id
|
||||
DISCORD_CLIENT_SECRET=your-discord-client-secret
|
||||
```
|
||||
|
||||
### 5. Adding the Necessary Routes and Pages
|
||||
|
||||
Let's define the necessary authentication Routes and Pages.
|
||||
|
||||
Add the following code to your `main.wasp` file:
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
// ...
|
||||
|
||||
// 6. Define the routes
|
||||
route LoginRoute { path: "/login", to: LoginPage }
|
||||
page LoginPage {
|
||||
component: import { Login } from "@src/pages/auth.jsx"
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
// ...
|
||||
|
||||
// 6. Define the routes
|
||||
route LoginRoute { path: "/login", to: LoginPage }
|
||||
page LoginPage {
|
||||
component: import { Login } from "@src/pages/auth.tsx"
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
We'll define the React components for these pages in the `src/pages/auth.{jsx,tsx}` file below.
|
||||
|
||||
### 6. Creating the Client Pages
|
||||
|
||||
:::info
|
||||
We are using [Tailwind CSS](https://tailwindcss.com/) to style the pages. Read more about how to add it [here](../../project/css-frameworks).
|
||||
:::
|
||||
|
||||
Let's create a `auth.{jsx,tsx}` file in the `src/pages` folder and add the following to it:
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```tsx title="src/pages/auth.jsx"
|
||||
import { LoginForm } from 'wasp/client/auth'
|
||||
|
||||
export function Login() {
|
||||
return (
|
||||
<Layout>
|
||||
<LoginForm />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// A layout component to center the content
|
||||
export function Layout({ children }) {
|
||||
return (
|
||||
<div className="w-full h-full bg-white">
|
||||
<div className="min-w-full min-h-[75vh] flex items-center justify-center">
|
||||
<div className="w-full h-full max-w-sm p-5 bg-white">
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```tsx title="src/pages/auth.tsx"
|
||||
import { LoginForm } from 'wasp/client/auth'
|
||||
|
||||
export function Login() {
|
||||
return (
|
||||
<Layout>
|
||||
<LoginForm />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// A layout component to center the content
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="w-full h-full bg-white">
|
||||
<div className="min-w-full min-h-[75vh] flex items-center justify-center">
|
||||
<div className="w-full h-full max-w-sm p-5 bg-white">
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
We imported the generated Auth UI components and used them in our pages. Read more about the Auth UI components [here](../../auth/ui).
|
||||
|
||||
### Conclusion
|
||||
|
||||
Yay, we've successfully set up Discord Auth! 🎉
|
||||
|
||||
![Discord Auth](/img/auth/discord.png)
|
||||
|
||||
|
||||
Running `wasp db migrate-dev` and `wasp start` should now give you a working app with authentication.
|
||||
To see how to protect specific pages (i.e., hide them from non-authenticated users), read the docs on [using auth](../../auth/overview).
|
||||
|
||||
## Default Behaviour
|
||||
|
||||
Add `discord: {}` to the `auth.methods` dictionary to use it with default settings.
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title=main.wasp
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
// highlight-next-line
|
||||
discord: {}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title=main.wasp
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
// highlight-next-line
|
||||
discord: {}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<DefaultBehaviour />
|
||||
|
||||
## Overrides
|
||||
|
||||
<OverrideIntro />
|
||||
|
||||
### Data Received From Discord
|
||||
|
||||
We are using Discord's API and its `/users/@me` endpoint to get the user data.
|
||||
|
||||
The data we receive from Discord on the `/users/@me` endpoint looks something this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "80351110224678912",
|
||||
"username": "Nelly",
|
||||
"discriminator": "1337",
|
||||
"avatar": "8342729096ea3675442027381ff50dfe",
|
||||
"verified": true,
|
||||
"flags": 64,
|
||||
"banner": "06c16474723fe537c283b8efa61a30c8",
|
||||
"accent_color": 16711680,
|
||||
"premium_type": 1,
|
||||
"public_flags": 64,
|
||||
"avatar_decoration_data": {
|
||||
"sku_id": "1144058844004233369",
|
||||
"asset": "a_fed43ab12698df65902ba06727e20c0e"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The fields you receive will depend on the scopes you requested. The default scope is set to `identify` only. If you want to get the email, you need to specify the `email` scope in the `configFn` function.
|
||||
|
||||
<small>
|
||||
|
||||
For an up to date info about the data received from Discord, please refer to the [Discord API documentation](https://discord.com/developers/docs/resources/user#user-object-user-structure).
|
||||
</small>
|
||||
|
||||
### Using the Data Received From Discord
|
||||
|
||||
<OverrideExampleIntro />
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
discord: {
|
||||
// highlight-next-line
|
||||
configFn: import { getConfig } from "@src/auth/discord.js",
|
||||
// highlight-next-line
|
||||
userSignupFields: import { userSignupFields } from "@src/auth/discord.js"
|
||||
}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
|
||||
entity User {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
avatarUrl String
|
||||
psl=}
|
||||
|
||||
// ...
|
||||
```
|
||||
|
||||
```js title=src/auth/discord.js
|
||||
export const userSignupFields = {
|
||||
username: (data) => data.profile.global_name,
|
||||
avatarUrl: (data) => data.profile.avatar,
|
||||
};
|
||||
|
||||
export function getConfig() {
|
||||
return {
|
||||
scopes: ['identify'],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
discord: {
|
||||
// highlight-next-line
|
||||
configFn: import { getConfig } from "@src/auth/discord.js",
|
||||
// highlight-next-line
|
||||
userSignupFields: import { userSignupFields } from "@src/auth/discord.js"
|
||||
}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
|
||||
entity User {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
username String @unique
|
||||
avatarUrl String
|
||||
psl=}
|
||||
|
||||
// ...
|
||||
```
|
||||
|
||||
```ts title=src/auth/discord.ts
|
||||
import { defineUserSignupFields } from 'wasp/server/auth'
|
||||
|
||||
export const userSignupFields = defineUserSignupFields({
|
||||
username: (data: any) => data.profile.global_name,
|
||||
avatarUrl: (data: any) => data.profile.avatar,
|
||||
})
|
||||
|
||||
export function getConfig() {
|
||||
return {
|
||||
scopes: ['identify'],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<GetUserFieldsType />
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Using Auth
|
||||
|
||||
<UsingAuthNote />
|
||||
|
||||
## API Reference
|
||||
|
||||
<ApiReferenceIntro />
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
discord: {
|
||||
// highlight-next-line
|
||||
configFn: import { getConfig } from "@src/auth/discord.js",
|
||||
// highlight-next-line
|
||||
userSignupFields: import { userSignupFields } from "@src/auth/discord.js"
|
||||
}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```wasp title="main.wasp"
|
||||
app myApp {
|
||||
wasp: {
|
||||
version: "^0.14.0"
|
||||
},
|
||||
title: "My App",
|
||||
auth: {
|
||||
userEntity: User,
|
||||
methods: {
|
||||
discord: {
|
||||
// highlight-next-line
|
||||
configFn: import { getConfig } from "@src/auth/discord.js",
|
||||
// highlight-next-line
|
||||
userSignupFields: import { userSignupFields } from "@src/auth/discord.js"
|
||||
}
|
||||
},
|
||||
onAuthFailedRedirectTo: "/login"
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The `discord` dict has the following properties:
|
||||
|
||||
- #### `configFn: ExtImport`
|
||||
|
||||
This function should return an object with the scopes for the OAuth provider.
|
||||
|
||||
<Tabs groupId="js-ts">
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```js title=src/auth/discord.js
|
||||
export function getConfig() {
|
||||
return {
|
||||
scopes: [],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ts" label="TypeScript">
|
||||
|
||||
```ts title=src/auth/discord.ts
|
||||
export function getConfig() {
|
||||
return {
|
||||
scopes: [],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
- #### `userSignupFields: ExtImport`
|
||||
|
||||
<UserSignupFieldsExplainer />
|
||||
|
||||
Read more about the `userSignupFields` function [here](../overview#1-defining-extra-fields).
|
@ -2,7 +2,7 @@
|
||||
title: Auth UI
|
||||
---
|
||||
|
||||
import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill, KeycloakPill } from "./Pills";
|
||||
import { EmailPill, UsernameAndPasswordPill, GithubPill, GooglePill, KeycloakPill, DiscordPill } from "./Pills";
|
||||
|
||||
To make using authentication in your app as easy as possible, Wasp generates the server-side code but also the client-side UI for you. It enables you to quickly get the login, signup, password reset and email verification flows in your app.
|
||||
|
||||
@ -110,7 +110,7 @@ The following components are available for you to use in your app:
|
||||
|
||||
### Login Form
|
||||
|
||||
Used with <UsernameAndPasswordPill />, <EmailPill />, <GithubPill />, <GooglePill /> and <KeycloakPill /> authentication.
|
||||
Used with <UsernameAndPasswordPill />, <EmailPill />, <GithubPill />, <GooglePill />, <KeycloakPill />, and <DiscordPill /> authentication.
|
||||
|
||||
![Login form](/img/authui/login.png)
|
||||
|
||||
@ -165,7 +165,7 @@ It will automatically show the correct authentication providers based on your `m
|
||||
|
||||
### Signup Form
|
||||
|
||||
Used with <UsernameAndPasswordPill />, <EmailPill />, <GithubPill />, <GooglePill /> and <KeycloakPill /> authentication.
|
||||
Used with <UsernameAndPasswordPill />, <EmailPill />, <GithubPill />, <GooglePill />, <KeycloakPill />, and <DiscordPill /> authentication.
|
||||
|
||||
![Signup form](/img/authui/signup.png)
|
||||
|
||||
|
@ -71,6 +71,7 @@ module.exports = {
|
||||
'auth/social-auth/github',
|
||||
'auth/social-auth/google',
|
||||
'auth/social-auth/keycloak',
|
||||
'auth/social-auth/discord',
|
||||
],
|
||||
},
|
||||
'auth/entities/entities',
|
||||
|
@ -27,7 +27,12 @@ export function AuthMethodsGrid() {
|
||||
title: 'Keycloak',
|
||||
description: 'Users sign in with their Keycloak account',
|
||||
linkToDocs: '/docs/auth/social-auth/keycloak',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Discord',
|
||||
description: 'Users sign in with their Discord account',
|
||||
linkToDocs: '/docs/auth/social-auth/discord',
|
||||
},
|
||||
]
|
||||
return (
|
||||
<>
|
||||
|
BIN
web/static/img/auth/discord.png
Normal file
BIN
web/static/img/auth/discord.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
web/static/img/integrations-discord-1.png
Normal file
BIN
web/static/img/integrations-discord-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Loading…
Reference in New Issue
Block a user