Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 164 additions & 3 deletions docs/guides/authentication/auth0.md
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,170 @@
---
description: Integrating with Auth0.
sidebar_position: 6
sidebar_label: 🚧 Auth0
sidebar_label: Auth0
---

# 🚧 Integrating With Auth0
# Integrating With Auth0

This guide provides simple examples of using Auth0 authentication with ZenStack. While Auth0 offers various authentication methods, this guide assumes you understand Auth0's authentication basics and can obtain a user object after authentication.

## The basic premise of applying a custom session object to ZenStack.

This section explains how to apply a custom session object to ZenStack by creating a user object and providing it to the enhance function when creating the Prisma client.

Create a user object and provide it to the enhance function when creating the Prisma client.

```ts
export const getPrisma = async (req) => {
const user = await getAuthenticatedAuth0User(req);
return enhance(user);
};
Comment thread
Driptap marked this conversation as resolved.
```

You can provide a type in the ZModel to express what the contents of the user object is.

```prisma
type Auth {
id String @id
specialKey String
@@auth
}
```

## Adding Auth0 authentication

You can authenticate an Auth0 user and extract information from the authentication and apply it to the ZenStack session.

Here's an example using a JWT:

```ts
export const getPrismaJWT = async (req) => {
try {
const jwks = jose.createRemoteJWKSet(new URL(process.env.AUTH0_JWKS_URI));
const token = toString(req.headers.get('authorization')).replace('Bearer ', '');
const res = await jose.jwtVerify(token, jwks, {
issuer: `${process.env.AUTH0_ISSUER_BASE_URL}/`,
audience: process.env.AUTH0_AUDIENCE,
algorithms: ['RS256'],
});

const userId = res.payload.sub;
const user = {
id: userId,
specialKey: res.payload.metadata.specialKey
};

return enhance(prisma, {user});
catch (err) {
// unauthenticated error
}
};
```

This would populate your `auth()` in the Zmodel with the object you've just created from auth0; enabling checks like:

```prisma
@@allow('read, update, create', auth().id == this.id)
Comment thread
Driptap marked this conversation as resolved.
```

or

```prisma
@@allow('read, update, create', auth().specialKey == 'SUPERMAN')
```

You can add what you need to this variable and set the types for it as referred to in the *Enhancing the prisma client* section.


## Working along side a user model

You may want to keep a record of User's in your own database.

You can create your application in such a way that a lack of the user existing in the managed database triggers a process to create one, such as a user onboarding flow.

```ts
const currentUser = async (req) => {
const session = await getSession(req); // get your auth0 auth session

if (!session?.user.sub) {
throw new Error('UNAUTHENTICATED'); // Throw an error if the user isn't authenticated
}

const dbUser = await prisma.user.findUnique({ // Find the user in the db
where: { id: session.user.sub },
});

return {
Comment thread
Driptap marked this conversation as resolved.
id: session.user.sub,
dbUserExists: !isNull(dbUser), // If the user doesn't exist in the database, this variable can be set in the session
};
};

// Create the client using the currentUser
export const getPrisma = async (req) => {
const user = await currentUser(req);
return enhance(user);
};
```

You can use the result of this token to redirect a user to an onboarding flow, such as a signup form:

```ts
app.get('/', async (req, res) => {
const user = await currentUser(req);
if (!user.dbUserExists) {
res.redirect('/onboarding');
}
res.send('hello user');
});
```
Comment thread
Driptap marked this conversation as resolved.

and create a user record using the ID from the Auth0 session, here's a small example using the Auth0 React SDK:

```ts
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

const Profile = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
const { trigger, isMutating } = useCreateUser();

const createUser = useCallback(async (event: FormEvent<HTMLFormElement>) => {
const formData = new FormData(event.currentTarget);
const name = formData.get('name');

await trigger({
data: {
id: user.sub,
name: name,
},
});
}, [trigger, user])

return <UserForm onSubmit={createUser}/>
};
```


When the client is created, the database is queried using the contents of the Auth0 token.

In this case, the Auth type is what provide authentication, not the User model, for example:

```prisma
// Specify the auth type
type Auth {
id String @id
@@auth // And decorate it with @@auth to tell ZenStack to use this as the session object
}

// add your user model as a regular model
model User {
id String @id
name String?
email String?

// You can now use the Auth object, populated by Auth0, to write policies
@@allow('create, read, update, delete', auth().id == this.id)
}
```

Coming soon.