import { Code } from "@/components/Code"

<img align="right" src="/img/adapters/neo4j.svg" height="64" width="128" />

# Neo4j Adapter

## Resources

- [Neo4j documentation](https://neo4j.com/docs/)

## Setup

### Installation

```bash npm2yarn
npm install @auth/neo4j-adapter neo4j-driver
```

### Environment Variables

```sh
NEO4J_URI=bolt://localhost
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=abc
```

### Configuration

<Code>
<Code.Next>

```ts filename="./auth.ts"
import NextAuth from "next-auth"
import neo4j from "neo4j-driver"
import { Neo4jAdapter } from "@auth/neo4j-adapter"

const driver = neo4j.driver(
  process.env.NEO4J_URI,
  neo4j.auth.basic(process.env.NEO4J_USERNAME, process.env.NEO4J_PASSWORD)
)

const neo4jSession = driver.session()

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [],
  adapter: Neo4jAdapter(neo4jSession),
})
```

</Code.Next>
<Code.Qwik>

```ts filename="/src/routes/plugin@auth.ts"
import { QwikAuth$ } from "@auth/qwik"
import neo4j from "neo4j-driver"
import { Neo4jAdapter } from "@auth/neo4j-adapter"

const driver = neo4j.driver(
  import.meta.env.NEO4J_URI,
  neo4j.auth.basic(
    import.meta.env.NEO4J_USERNAME,
    import.meta.env.NEO4J_PASSWORD
  )
)

const neo4jSession = driver.session()

export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$(
  () => ({
    providers: [],
    adapter: Neo4jAdapter(neo4jSession),
  })
)
```

</Code.Qwik>
<Code.Svelte>

```ts filename="./src/auth.ts"
import { SvelteKitAuth } from "@auth/sveltekit"
import neo4j from "neo4j-driver"
import { Neo4jAdapter } from "@auth/neo4j-adapter"

const driver = neo4j.driver(
  process.env.NEO4J_URI,
  neo4j.auth.basic(process.env.NEO4J_USERNAME, process.env.NEO4J_PASSWORD)
)

const neo4jSession = driver.session()

export const { handle, signIn, signOut } = SvelteKitAuth({
  providers: [],
  adapter: Neo4jAdapter(neo4jSession),
})
```

</Code.Svelte>
<Code.Express>

```ts filename="./src/routes/auth.route.ts"
import { ExpressAuth } from "@auth/express"
import neo4j from "neo4j-driver"
import { Neo4jAdapter } from "@auth/neo4j-adapter"

const app = express()

const driver = neo4j.driver(
  process.env.NEO4J_URI,
  neo4j.auth.basic(process.env.NEO4J_USERNAME, process.env.NEO4J_PASSWORD)
)

const neo4jSession = driver.session()

app.set("trust proxy", true)
app.use(
  "/auth/*",
  ExpressAuth({
    providers: [],
    adapter: Neo4jAdapter(neo4jSession),
  })
)
```

</Code.Express>
</Code>

### Schema

#### Node labels

The following node labels are used.

- User
- Account
- Session
- VerificationToken

#### Relationships

The following relationships and relationship labels are used.

- `(:User)-[:HAS_ACCOUNT]->(:Account)`
- `(:User)-[:HAS_SESSION]->(:Session)`

#### Properties

This schema is adapted for use in Neo4j and is based upon our main [models](https://authjs.dev/reference/core/adapters#models). Please check there for the node properties. Relationships have no properties.

#### Indexes

Optimum indexes will vary on your edition of Neo4j i.e. community or enterprise, and in case you have your own additional data on the nodes. Below are basic suggested indexes.

1. For **both** Community Edition & Enterprise Edition create constraints and indexes

```sql
CREATE CONSTRAINT user_id_constraint IF NOT EXISTS
ON (u:User) ASSERT u.id IS UNIQUE;

CREATE INDEX user_id_index IF NOT EXISTS
FOR (u:User) ON (u.id);

CREATE INDEX user_email_index IF NOT EXISTS
FOR (u:User) ON (u.email);

CREATE CONSTRAINT session_session_token_constraint IF NOT EXISTS
ON (s:Session) ASSERT s.sessionToken IS UNIQUE;

CREATE INDEX session_session_token_index IF NOT EXISTS
FOR (s:Session) ON (s.sessionToken);
```

2a. For Community Edition **only** create single-property indexes

```sql
CREATE INDEX account_provider_index IF NOT EXISTS
FOR (a:Account) ON (a.provider);

CREATE INDEX account_provider_account_id_index IF NOT EXISTS
FOR (a:Account) ON (a.providerAccountId);

CREATE INDEX verification_token_identifier_index IF NOT EXISTS
FOR (v:VerificationToken) ON (v.identifier);

CREATE INDEX verification_token_token_index IF NOT EXISTS
FOR (v:VerificationToken) ON (v.token);
```

2b. For Enterprise Edition **only** create composite node key constraints and indexes

```sql
CREATE CONSTRAINT account_provider_composite_constraint IF NOT EXISTS
ON (a:Account) ASSERT (a.provider, a.providerAccountId) IS NODE KEY;

CREATE INDEX account_provider_composite_index IF NOT EXISTS
FOR (a:Account) ON (a.provider, a.providerAccountId);

CREATE CONSTRAINT verification_token_composite_constraint IF NOT EXISTS
ON (v:VerificationToken) ASSERT (v.identifier, v.token) IS NODE KEY;

CREATE INDEX verification_token_composite_index IF NOT EXISTS
FOR (v:VerificationToken) ON (v.identifier, v.token);
```
