Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.

Commit 36e357e

Browse files
authored
Merge pull request #4 from passageidentity/users/kf/passage-profile-integration
Add Passage Profile Example
2 parents 50945f0 + 6172912 commit 36e357e

File tree

20 files changed

+452
-13
lines changed

20 files changed

+452
-13
lines changed

01-Login/README.md

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
1+
# Passage Next.js Example App
2+
3+
This example application uses the [Passage Auth Element](https://www.npmjs.com/package/@passageidentity/passage-elements) in a Next.js application to authenticate users using biometrics or magic links.
4+
[Passage Node.js SDK](https://www.npmjs.com/package/@passageidentity/passage-node) is used to verify users on authenticated endpoints. To run this example application, follow the instructions below.
5+
6+
## Configure Your Environment Variables
7+
8+
1. Copy the EXAMPLE.env file to your own .env file.
9+
2. Replace the example variables with your own Passage App ID and API Key. You can get these from the [Passage Console](https://console.passage.id).
210

311
## Getting Started
412

@@ -18,17 +26,36 @@ You can start editing the page by modifying `pages/index.js`. The page auto-upda
1826

1927
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
2028

21-
## Learn More
22-
23-
To learn more about Next.js, take a look at the following resources:
29+
# Using Passage with Next.js
2430

25-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31+
## Importing and Using the Passage-Auth Custom Element
32+
The easiest way to add authentication to a web frontend is with a Passage Auth custom element. First you'll need to install the [passage-elements](https://www.npmjs.com/package/@passageidentity/passage-elements) package from npm:
33+
```
34+
npm i --save @passageidentity/passage-elements
35+
```
36+
Importing `@passageidentity/passage-elements/passage-auth` triggers a side-effect that will register the passage-auth custom element with the client browser for usage. Since Next.js pre-renders pages on the server this presents a common issue with using web components, such as the Passage elements, in pre-rendered pages - when the server side pre-render occurs there is no client window defined to call `window.customElements.define()` on, which results in an error being thrown.
37+
38+
The most common solution when using custom elements in pre-rendered applications is to defer the registration of the custom element to a lifecycle hook so that the code is only executed when the client app is executed in browser. This is done in this example in [pages/index.js](https://github.com/passageidentity/example-nextjs/blob/main/pages/index.js):
39+
```javascript
40+
export default function Home() {
41+
42+
useEffect(()=>{
43+
require('@passageidentity/passage-elements/passage-auth');
44+
}, []);
45+
46+
return (
47+
<div>
48+
...
49+
</div>
50+
)
51+
}
52+
```
2753

28-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
54+
## Getting Authentication Status and User Information with Server-Side Rendering
55+
After the user has logged in with Passage, all requests need to be authenticated using the JWT provided by Passage. The [Passage Node.js SDK](https://www.npmjs.com/package/@passageidentity/passage-node) to authenticate requests and retrieve user data for your application.
2956

30-
## Deploy on Vercel
57+
In this example, we handle authentication securely in Next.js's server-side rendering function [`getServerSideProps()`](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering). Per Next.js documention you can import modules in top-level scope for use in `getServerSideProps`. Imports used in `getServerSideProps` will not be bundled for the client-side. This means you can write server-side code directly in `getServerSideProps`.
3158

32-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
59+
The JWT provided by Passage is stored in both cookies and localstorage. Next.js provides the cookies set for an application to `getServerSideProps` which allows passing the JWT from the client browser to the server to handle authentication.
3360

34-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
61+
This is done in this example in pages/dashboard.js.

01-Login/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"lint": "next lint"
99
},
1010
"dependencies": {
11-
"@passageidentity/passage-auth": "latest",
11+
"@passageidentity/passage-elements": "latest",
1212
"@passageidentity/passage-node": "^1.2.0",
1313
"next": "12.0.10",
1414
"react": "17.0.2",

01-Login/pages/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
22

33
export default function Home({appID}) {
44
useEffect(()=>{
5-
require('@passageidentity/passage-auth');
5+
require('@passageidentity/passage-elements/passage-auth');
66
}, []);
77

88
return (

01-Login/styles/globals.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ body {
44
margin: 0;
55
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
66
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7+
background-color: #E5E5E5;
78
}
89

910
a {

02-Login-With-Profile/.eslintrc.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "next/core-web-vitals",
3+
"rules": {
4+
"semi": ["warn", "always"],
5+
"semi-style": ["warn", "last"]
6+
}
7+
}

02-Login-With-Profile/.gitignore

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Diagnostic reports (https://nodejs.org/api/report.html)
10+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
*.pid.lock
17+
18+
# Directory for instrumented libs generated by jscoverage/JSCover
19+
lib-cov
20+
21+
# Coverage directory used by tools like istanbul
22+
coverage
23+
*.lcov
24+
25+
# nyc test coverage
26+
.nyc_output
27+
28+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29+
.grunt
30+
31+
# Bower dependency directory (https://bower.io/)
32+
bower_components
33+
34+
# node-waf configuration
35+
.lock-wscript
36+
37+
# Compiled binary addons (https://nodejs.org/api/addons.html)
38+
build/Release
39+
40+
# Dependency directories
41+
node_modules/
42+
jspm_packages/
43+
44+
# TypeScript v1 declaration files
45+
typings/
46+
47+
# TypeScript cache
48+
*.tsbuildinfo
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Microbundle cache
57+
.rpt2_cache/
58+
.rts2_cache_cjs/
59+
.rts2_cache_es/
60+
.rts2_cache_umd/
61+
62+
# Optional REPL history
63+
.node_repl_history
64+
65+
# Output of 'npm pack'
66+
*.tgz
67+
68+
# Yarn Integrity file
69+
.yarn-integrity
70+
71+
# dotenv environment variables file
72+
.env
73+
.env.test
74+
75+
# parcel-bundler cache (https://parceljs.org/)
76+
.cache
77+
78+
# Next.js build output
79+
.next
80+
81+
# Nuxt.js build / generate output
82+
.nuxt
83+
dist
84+
85+
# Gatsby files
86+
.cache/
87+
# Comment in the public line in if your project uses Gatsby and *not* Next.js
88+
# https://nextjs.org/blog/next-9-1#public-directory-support
89+
# public
90+
91+
# vuepress build output
92+
.vuepress/dist
93+
94+
# Serverless directories
95+
.serverless/
96+
97+
# FuseBox cache
98+
.fusebox/
99+
100+
# DynamoDB Local files
101+
.dynamodb/
102+
103+
# TernJS port file
104+
.tern-port
105+
106+
# DS_Store file
107+
.DS_Store
108+
109+
# package-lock
110+
package-lock.json

02-Login-With-Profile/EXAMPLE.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
PASSAGE_APP_ID=
2+
PASSAGE_API_KEY=

02-Login-With-Profile/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Passage Next.js Example App
2+
3+
This example application uses the [Passage Auth Element](https://www.npmjs.com/package/@passageidentity/passage-elements) in a Next.js application to authenticate users using biometrics or magic links.
4+
[Passage Node.js SDK](https://www.npmjs.com/package/@passageidentity/passage-node) is used to verify users on authenticated endpoints. To run this example application, follow the instructions below.
5+
6+
## Configure Your Environment Variables
7+
8+
1. Copy the EXAMPLE.env file to your own .env file.
9+
2. Replace the example variables with your own Passage App ID and API Key. You can get these from the [Passage Console](https://console.passage.id).
10+
11+
## Getting Started
12+
13+
First, run the development server:
14+
15+
```bash
16+
npm run dev
17+
# or
18+
yarn dev
19+
```
20+
21+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
22+
23+
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
24+
25+
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
26+
27+
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
28+
29+
# Using Passage with Next.js
30+
31+
## Importing and Using the Passage Custom Elements
32+
The easiest way to add authentication to a web frontend is with a Passage Auth custom element. First you'll need to install the [passage-elements](https://www.npmjs.com/package/@passageidentity/passage-elements) package from npm:
33+
```
34+
npm i --save @passageidentity/passage-elements
35+
```
36+
Importing `@passageidentity/passage-elements/passage-auth` triggers a side-effect that will register the passage-auth custom element with the client browser for usage. Since Next.js pre-renders pages on the server this presents a common issue with using web components, such as the Passage elements, in pre-rendered pages - when the server side pre-render occurs there is no client window defined to call `window.customElements.define()` on, which results in an error being thrown.
37+
38+
The most common solution when using custom elements in pre-rendered applications is to defer the registration of the custom element to a lifecycle hook so that the code is only executed when the client app is executed in browser. This is done in this example in [pages/index.js](https://github.com/passageidentity/example-nextjs/blob/main/pages/index.js):
39+
```javascript
40+
export default function Home() {
41+
42+
useEffect(()=>{
43+
require('@passageidentity/passage-elements/passage-auth');
44+
}, []);
45+
46+
return (
47+
<div>
48+
...
49+
</div>
50+
)
51+
}
52+
```
53+
54+
Similarly for the dashboard in this example we use the passage-profile element to display user information. The profile element is imported in the same way the auth element is imported:
55+
```javascript
56+
function Dashboard({isAuthorized, appID}){
57+
58+
useEffect(()=>{
59+
require('@passageidentity/passage-elements/passage-profile');
60+
}, []);
61+
62+
}
63+
```
64+
65+
## Getting Authentication Status and User Information with Server-Side Rendering
66+
After the user has logged in with Passage, all requests need to be authenticated using the JWT provided by Passage. The [Passage Node.js SDK](https://www.npmjs.com/package/@passageidentity/passage-node) to authenticate requests and retrieve user data for your application.
67+
68+
In this example, we handle authentication securely in Next.js's server-side rendering function [`getServerSideProps()`](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering). Per Next.js documention you can import modules in top-level scope for use in `getServerSideProps`. Imports used in `getServerSideProps` will not be bundled for the client-side. This means you can write server-side code directly in `getServerSideProps`.
69+
70+
The JWT provided by Passage is stored in both cookies and localstorage. Next.js provides the cookies set for an application to `getServerSideProps` which allows passing the JWT from the client browser to the server to handle authentication.
71+
72+
This is done in this example in pages/dashboard.js.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import styles from '../styles/Banner.module.css';
2+
3+
export default function Banner() {
4+
return (
5+
<div className={styles.mainHeader}>
6+
<a href="https://passage.id/" ><div className={styles.passageLogo}></div></a>
7+
<div className={styles.headerText}>Passage + Next.js Example App</div>
8+
<div className={styles.spacer}></div>
9+
<a href="https://passage.id/" ><span className={styles.text}>Go to Passage</span></a>
10+
</div>
11+
);
12+
}

02-Login-With-Profile/next.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
reactStrictMode: true,
3+
}

02-Login-With-Profile/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "passage-next-app",
3+
"private": true,
4+
"scripts": {
5+
"dev": "next dev",
6+
"build": "next build",
7+
"start": "next start",
8+
"lint": "next lint"
9+
},
10+
"dependencies": {
11+
"@passageidentity/passage-elements": "latest",
12+
"@passageidentity/passage-node": "^1.2.0",
13+
"next": "12.0.10",
14+
"react": "17.0.2",
15+
"react-dom": "17.0.2"
16+
},
17+
"devDependencies": {
18+
"eslint": "8.8.0",
19+
"eslint-config-next": "12.0.10"
20+
}
21+
}

02-Login-With-Profile/pages/_app.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import '../styles/globals.css';
2+
3+
import Banner from '../components/banner';
4+
import styles from '../styles/App.module.css';
5+
6+
function MyApp({ Component, pageProps }) {
7+
return (
8+
<>
9+
<Banner></Banner>
10+
<div className={styles.mainContainer}>
11+
<Component {...pageProps} />
12+
</div>
13+
<div className={styles.footer}>
14+
Learn more with our <u><a href="https://docs.passage.id">Documentation</a></u> and <u><a href="https://github.com/passageidentity">Github</a></u>.
15+
</div>
16+
</>
17+
);
18+
}
19+
20+
export default MyApp;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2+
3+
export default function handler(req, res) {
4+
res.status(200).json({ name: 'John Doe' })
5+
}

0 commit comments

Comments
 (0)