Skip to content

Commit

Permalink
feat(providers): Add Loops Email Provider and Documentation (#11197)
Browse files Browse the repository at this point in the history
Co-authored-by: Nico Domino <yo@ndo.dev>
  • Loading branch information
Whats-A-MattR and ndom91 authored Nov 27, 2024
1 parent 3df6ff9 commit 3ec0684
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 10 deletions.
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/2_bug_provider.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ body:
- "Kinde"
- "Line"
- "LinkedIn"
- "Loops"
- "Mailchimp"
- "Mail.ru"
- "Mastodon"
Expand Down
149 changes: 148 additions & 1 deletion docs/pages/getting-started/authentication/email.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ This login mechanism starts by the user providing their email address at the log
>
<img className="size-16" src={`/img/providers/postmark.svg`} />
<div className="text-sm text-center">Postmark</div>
</RichTabs.Trigger>
<RichTabs.Trigger
value="loops"
orientation="vertical"
className="!border border-neutral-200 dark:border-neutral-700 aria-selected:!bg-neutral-100 aria-selected:dark:!bg-neutral-950 dark:!bg-neutral-900 !bg-white !h-auto !w-auto !gap-2 !justify-start p-6 px-8 rounded-md outline-none transition-all duration-300 hover:bg-neutral-200 !font-normal"
>
<img className="size-16" src={`/img/providers/loops.svg`} />
<div className="text-sm text-center">Loops</div>
</RichTabs.Trigger>
<RichTabs.Trigger
value="mailgun"
Expand Down Expand Up @@ -1039,6 +1047,145 @@ Start your application, once the user enters their Email and clicks on the signi

For more information on this provider go to the [Postmark docs page](/getting-started/providers/postmark).

</RichTabs.Content>
<RichTabs.Content
orientation="vertical"
value="loops"
className="h-full !border-0 !w-full"
tabIndex={-1}>

### Loops Setup

<Steps>

### Database Adapter

Please make sure you've [setup a database adapter](/getting-started/database), as mentioned earlier,
a database is required for passwordless login to work as verification tokens need to be stored.

### Create your Transactional Email Template on Loops

Loops have provided a super handy [guide](https://loops.so/docs/transactional/guide) to help you get started with creating your transactional email template.
This provider only passes one data varaiable into the template, `url` which is the magic link to sign in. This is case sensitive, so make sure you use `url` in your template. <br/>
On the last page of Template creation, you'll need to copy the `TRANSACTIONAL ID`. If you skipped this step, don't worry, you can get this at any from the Template edit page.

### Create an API Key on Loops

You'll need to create an API key to authenticate with Loops. This key should be kept secret and not shared with anyone.
You can Generate a key by going to the [API Settings Page](https://app.loops.so/settings?page=api) and clicking Generate.
You should name the key something that makes sense to you, like "Auth.js".

### Setup Environment Variables

To implement Loops, you need to set up the following environment variables. You should have these from the previous steps.

```bash filename=".env"
AUTH_LOOPS_KEY=abc123
AUTH_LOOPS_TRANSACTIONAL_ID=def456
```

### Setup Provider

Let's enable `Loops` as a sign-in option for our Auth.js configuration. You'll have to import the `Loops` provider from the package and pass it to the providers array we set up earlier in the Auth.js config file:

<Code>
<Code.Next>

```ts filename="./auth.ts"
import NextAuth from "next-auth"
import Loops from "next-auth/providers/loops"

export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
Loops({
apiKey: process.env.AUTH_LOOPS_KEY,
transactionalId: process.env.AUTH_LOOPS_TRANSACTIONAL_ID,
}),
],
})
```

</Code.Next>
<Code.Svelte>

```ts filename="./src/auth.ts"
import SvelteKitAuth from "@auth/sveltekit"
import Loops from "@auth/sveltekit/providers/loops"
import {
AUTH_LOOPS_KEY,
AUTH_LOOPS_TRANSACTIONAL_ID,
} from "$env/static/private"

export const { handle, signIn, signOut } = SvelteKitAuth({
providers: [
Loops({
apiKey: AUTH_LOOPS_KEY,
transactionalId: AUTH_LOOPS_TRANSACTIONAL_ID,
}),
],
})
```

```ts filename="./src/hooks.server.ts"
export { handle } from "./auth"
```

</Code.Svelte>
</Code>

### Add Signin Button

Next, we add a signin button somewhere in your application like the Navbar. This will send an email to the user containing the magic link to sign in.

<Code>
<Code.Next>

```tsx filename="./components/sign-in.tsx"
import { signIn } from "../../auth.ts"

export function SignIn() {
return (
<form
action={async (formData) => {
"use server"
await signIn("loops", formData)
}}
>
<input type="text" name="email" placeholder="Email" />
<button type="submit">Sign in with Loops</button>
</form>
)
}
```

</Code.Next>
<Code.Svelte>

```ts filename="src/routes/+page.svelte"

<script lang="ts">
import { SignIn } from "@auth/sveltekit/components"
</script>

<div>
<nav>
<img src="/img/logo.svg" alt="Company Logo" />
<SignIn provider="loops"/>
</nav>
</div>

```

</Code.Svelte>
</Code>

### Signin

Start your application, click on the signin button we just added, and you should see Auth.js built-in sign in page with the option to sign in with your email.
A user can enter their email, click "Sign in with Loops", and receive their beautifully formatted signin email.
Clicking on the link in the email will redirect the user to your application, landing already authenticated!

</Steps>
</RichTabs.Content>
<RichTabs.Content
orientation="vertical"
Expand Down Expand Up @@ -1194,5 +1341,5 @@ Start your application, once the user enters their Email and clicks on the signi
For more information on this provider go to the [Mailgun docs page](/getting-started/providers/mailgun).

</RichTabs.Content>
</RichTabs>
</RichTabs>
</div>
103 changes: 103 additions & 0 deletions docs/pages/getting-started/providers/loops.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Callout } from "nextra/components"
import { Code } from "@/components/Code"

<img align="right" src="/img/providers/loops.svg" height="96" />

# Loops Provider

## Overview

The Loops provider uses email to send "magic links" that contain URLs with verification tokens can be used to sign in.

Adding support for signing in via email in addition to one or more OAuth services provides a way for users to sign in if they lose access to their OAuth account (e.g. if it is locked or deleted).

The Loops provider can be used in conjunction with (or instead of) one or more OAuth providers.

## How it works

On initial sign in, a **Verification Token** is sent to the email address provided. By default this token is valid for 24 hours. If the Verification Token is used within that time (i.e. by clicking on the link in the email) an account is created for the user and they are signed in.

If someone provides the email address of an _existing account_ when signing in, an email is sent and they are signed into the account associated with that email address when they follow the link in the email.

<Callout type="warning">
The Loops provider can be used with both JSON Web Token and database managed
sessions, however **you must configure a database** to use it. It is not
possible to enable email sign in without using a database.
</Callout>

## Configuration

### Add and Verify your Domain on Loops

First, you'll need to have completed the steps covered in the ['Start here'](https://loops.so/docs/start-here) Loops documentation.
The main thing required is to [set up your domain records](https://loops.so/docs/start-here#1-set-up-your-domain-records).

### Generate an API Key

Next, you will have to generate an API key in the [Loops Dashboard](https://loops.so/api-keys). You can save this API key as the `AUTH_LOOPS_KEY` environment variable.

```sh
AUTH_LOOPS_KEY=abc
```

### Create a Transactional Email Template on Loops

The easiest way to achieve this is using the [Loops email editor](https://loops.so/docs/creating-emails/editor) to create a transactional email template.
If you're new to Loops, you can find rich documentation [here](https://loops.so/docs/transactional/guide).

<br />
Copy the Transactional ID value from the last page of the template creation
process, and save this as the `AUTH_LOOPS_TRANSACTIONAL_ID` environment
variable. If you're following these steps, you should now have two environment
variables set up for Loops.

```sh
AUTH_LOOPS_KEY=abc
AUTH_LOOPS_TRANSACTIONAL_ID=def
```

<Callout type="warning">
When creating your email template, make sure to include the `url` variable in
the template. This is the URL that will sent to the user, allowing them to
signin.
</Callout>

<Code>
<Code.Next>
### Configure AuthJS with the Loops Provider
```ts filename="./auth.ts"
import NextAuth from "next-auth"
import Loops from "next-auth/providers/loops"

export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: ..., // database adapter of your choosing
providers: [
Loops({
apiKey: process.env.AUTH_LOOPS_KEY,
transactionalId: process.env.AUTH_LOOPS_TRANSACTIONAL_ID,
}),
],
})
```

</Code.Next>
<Code.Svelte>
### Configure AuthJS with the Loops Provider
```ts filename="./src/auth.ts"
import { SvelteKitAuth } from "@auth/sveltekit"
import Loops from "@auth/sveltekit/providers/loops"
import { AUTH_LOOPS_KEY, AUTH_LOOPS_TRANSACTIONAL_ID } from "@env/static/private"

export const { handle, signIn, signOut } = SvelteKitAuth({
adapter: ..., // database adapter of your choosing
providers: [
Loops({
apiKey: AUTH_LOOPS_KEY,
transactionalId: AUTH_LOOPS_TRANSACTIONAL_ID,
}),
],
})
```

</Code.Svelte>
</Code>
3 changes: 3 additions & 0 deletions docs/public/img/providers/loops.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 17 additions & 9 deletions packages/core/src/providers/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,29 @@ export default function Email(config: NodemailerUserConfig): NodemailerConfig {
}
}

// TODO: Rename to Token provider
// when started working on https://github.com/nextauthjs/next-auth/discussions/1465
export type EmailProviderType = "email"

export type EmailProviderSendVerificationRequestParams = {
identifier: string
url: string
expires: Date
provider: EmailConfig
token: string
theme: Theme
request: Request
}

export interface EmailConfig extends CommonProviderOptions {
id: string
type: "email"
name: string
from?: string
maxAge?: number
sendVerificationRequest: (params: {
identifier: string
url: string
expires: Date
provider: EmailConfig
token: string
theme: Theme
request: Request
}) => Awaitable<void>
sendVerificationRequest: (
params: EmailProviderSendVerificationRequestParams
) => Awaitable<void>
/** Used to hash the verification token. */
secret?: string
/** Used with HTTP-based email providers. */
Expand Down
Loading

0 comments on commit 3ec0684

Please sign in to comment.