@propelauth/nextjs 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -246
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<a href="https://www.propelauth.com?ref=github" target="_blank" align="center">
|
3
|
+
<img src="https://www.propelauth.com/imgs/lockup.svg" width="200">
|
4
|
+
</a>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
|
1
8
|
# PropelAuth Next.js (v13+) Library
|
2
9
|
|
3
10
|
[PropelAuth](https://www.propelauth.com?utm_source=github&utm_medium=library&utm_campaign=nextjs) is a user management and authentication service for your B2B/multi-tenant applications.
|
4
11
|
|
5
|
-
This library provides a simple way to integrate your Next.js application (either
|
6
|
-
|
7
|
-
Next.js SSR/AppRouter support is currently in beta.
|
12
|
+
This library provides a simple way to integrate your Next.js application (either App Router or Pages) with PropelAuth.
|
8
13
|
|
9
14
|
## Installation
|
10
15
|
|
@@ -12,297 +17,163 @@ Next.js SSR/AppRouter support is currently in beta.
|
|
12
17
|
npm install @propelauth/nextjs
|
13
18
|
```
|
14
19
|
|
15
|
-
##
|
16
|
-
|
17
|
-
Before you start, make sure you have a PropelAuth account. You can sign up for free at [here](https://auth.propelauth.com).
|
18
|
-
|
19
|
-
You'll need to set the following .env variables in your Next.js application:
|
20
|
-
|
21
|
-
- NEXT_PUBLIC_AUTH_URL
|
22
|
-
- PROPELAUTH_API_KEY
|
23
|
-
- PROPELAUTH_VERIFIER_KEY
|
24
|
-
- PROPELAUTH_REDIRECT_URI
|
25
|
-
|
26
|
-
You can find the NEXT_PUBLIC_AUTH_URL, PROPELAUTH_API_KEY, and PROPELAUTH_VERIFIER_KEY variables for your application in the PropelAuth Dashboard under Backend Integration.
|
27
|
-
|
28
|
-
When you copy the PROPELAUTH_VERIFIER_KEY from the PropelAuth dashboard, it will automatically paste into your .env file with line breaks. However, due to the way some systems interpret multiline environment variables, you will need to edit the verifier key value to include ‘\n’ instead of newline characters. For example:
|
29
|
-
|
30
|
-
```
|
31
|
-
PROPELAUTH_VERIFIER_KEY=-----BEGIN PUBLIC KEY-----\nMIIBIjANBgk...
|
32
|
-
```
|
20
|
+
## Automatic Installation
|
33
21
|
|
34
|
-
If
|
22
|
+
If you would prefer a manual installation process instead of an automatic one, check out the installation guides for [App Router](https://docs.propelauth.com/reference/fullstack-apis/nextjsapp/installation-and-setup) and [Pages Router](https://docs.propelauth.com/reference/fullstack-apis/nextjspages/installation-and-setup).
|
35
23
|
|
36
|
-
|
24
|
+
Begin by installing the PropelAuth CLI:
|
37
25
|
|
38
|
-
|
39
|
-
|
40
|
-
In your `src/app/api/auth/[slug]` directory, create a file called `route.ts` with the following content:
|
41
|
-
|
42
|
-
```typescript
|
43
|
-
import { getRouteHandlers } from '@propelauth/nextjs/server/app-router'
|
44
|
-
import { NextRequest } from 'next/server'
|
45
|
-
|
46
|
-
// postLoginRedirectPathFn is optional, but if you want to redirect the user to a different page after login, you can do so here.
|
47
|
-
const routeHandlers = getRouteHandlers({
|
48
|
-
postLoginRedirectPathFn: (req: NextRequest) => {
|
49
|
-
return '/'
|
50
|
-
},
|
51
|
-
})
|
52
|
-
export const GET = routeHandlers.getRouteHandler
|
53
|
-
export const POST = routeHandlers.postRouteHandler
|
26
|
+
```bash
|
27
|
+
npm i -g @propelauth/cli
|
54
28
|
```
|
55
29
|
|
56
|
-
|
30
|
+
## Logging into the PropelAuth CLI
|
57
31
|
|
58
|
-
|
32
|
+
Before we install PropelAuth in your Next.js project we first have to log into the CLI. If you haven't already created an account in PropelAuth, navigate to [auth.propelauth.com](https://auth.propelauth.com/en/signup) to get started.
|
59
33
|
|
60
|
-
|
34
|
+
Once you have an account with PropelAuth, run this command to login to the CLI:
|
61
35
|
|
62
|
-
```
|
63
|
-
|
64
|
-
return (
|
65
|
-
<html lang="en">
|
66
|
-
<AuthProvider authUrl={process.env.NEXT_PUBLIC_AUTH_URL}>
|
67
|
-
<body className={inter.className}>{children}</body>
|
68
|
-
</AuthProvider>
|
69
|
-
</html>
|
70
|
-
)
|
71
|
-
}
|
36
|
+
```bash
|
37
|
+
propelauth login
|
72
38
|
```
|
73
39
|
|
74
|
-
|
75
|
-
|
76
|
-
In your `_app.tsx` file, add the `AuthProvider`:
|
40
|
+
To login you'll be prompted to create and copy/paste a Personal API Key into your terminal.
|
77
41
|
|
78
|
-
```typescript jsx
|
79
|
-
export default function MyApp({Component, pageProps}: AppProps) {
|
80
|
-
return (
|
81
|
-
<AuthProvider authUrl={process.env.NEXT_PUBLIC_AUTH_URL}>
|
82
|
-
<Component {...pageProps} />
|
83
|
-
</AuthProvider>
|
84
|
-
)
|
85
|
-
}
|
86
42
|
```
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
// It should be called on every request that requires authentication AND /api/auth/.* routes.
|
99
|
-
export const config = {
|
100
|
-
matcher: [
|
101
|
-
// REQUIRED: Match all request paths that start with /api/auth/
|
102
|
-
'/api/auth/(.*)',
|
103
|
-
// OPTIONAL: Don't match any static assets
|
104
|
-
'/((?!_next/static|_next/image|favicon.ico).*)',
|
105
|
-
],
|
106
|
-
}
|
43
|
+
┌ ⚡ PropelAuth Login
|
44
|
+
│
|
45
|
+
●
|
46
|
+
│ Please visit the following URL to create a personal API key:
|
47
|
+
│
|
48
|
+
● https://auth.propelauth.com/api_keys/personal
|
49
|
+
│
|
50
|
+
│
|
51
|
+
◆ Enter your API key
|
52
|
+
│ # enter your API key here
|
53
|
+
└
|
107
54
|
```
|
108
55
|
|
109
|
-
|
56
|
+
You can create a Personal API Key by navigating to https://auth.propelauth.com/api_keys/personal and clicking **+ New API Key**.
|
110
57
|
|
111
|
-
### Get the user in Server Components (App Router example)
|
112
58
|
|
113
|
-
|
114
|
-
import { getUser } from '@propelauth/nextjs/server/app-router'
|
59
|
+
### Selecting a Default Project
|
115
60
|
|
116
|
-
|
117
|
-
const user = await getUser()
|
61
|
+
Once your API Key is validated the CLI will prompt you to select a default project, if desired. If you select a default project, the CLI will not prompt you to select a project again until you repeat the login process or run the `set-default-project` command.
|
118
62
|
|
119
|
-
if (user) {
|
120
|
-
return <div>Hello {user.firstName}!</div>
|
121
|
-
} else {
|
122
|
-
return <div>Please log in to be welcomed</div>
|
123
|
-
}
|
124
|
-
}
|
125
63
|
```
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
return <div>Hello {user.firstName}!</div>
|
135
|
-
}
|
64
|
+
┌
|
65
|
+
◇ ✓ Projects fetched successfully
|
66
|
+
│
|
67
|
+
◆ Select a project to use
|
68
|
+
│ ● Always ask which project to use (You will be prompted for each command)
|
69
|
+
│ ○ Acme Inc / New Project
|
70
|
+
└
|
136
71
|
```
|
137
72
|
|
138
|
-
|
73
|
+
## Installing and Setting up PropelAuth in Next.js
|
139
74
|
|
140
|
-
|
141
|
-
import { GetServerSideProps, InferGetServerSidePropsType } from 'next'
|
142
|
-
import { getUserFromServerSideProps } from '@propelauth/nextjs/server/pages'
|
143
|
-
import { User } from '@propelauth/nextjs/client'
|
75
|
+
Once you have logged into the CLI it's time to install PropelAuth within your Next.js app! Navigate to your Next.js project directory and run the following command:
|
144
76
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
77
|
+
```bash
|
78
|
+
propelauth setup
|
79
|
+
```
|
80
|
+
|
81
|
+
During installation you'll see the following prompts:
|
82
|
+
|
83
|
+
```
|
84
|
+
┌ ⚡ PropelAuth Setup
|
85
|
+
│
|
86
|
+
◆ Select your project framework:
|
87
|
+
│ ○ Next.js (App Router)
|
88
|
+
│ ● Next.js (Pages Router) (Uses pages/ directory structure)
|
89
|
+
│
|
90
|
+
◆ Select a project to use for this command
|
91
|
+
│ ● Acme Inc / New Project
|
92
|
+
│
|
93
|
+
◆ Enter the URL your Next.js app runs on:
|
94
|
+
│ ↳ http://localhost:3000
|
95
|
+
│
|
96
|
+
● No API key found in environment file
|
97
|
+
│
|
98
|
+
◆ Would you like to generate a new Backend Integration API Key for this project?
|
99
|
+
│ ● yes / ○ no
|
100
|
+
│
|
101
|
+
│ Enter a name for the new Backend Integration API Key:
|
102
|
+
│ ↳ Next.js Integration
|
103
|
+
│
|
104
|
+
● Updates needed for the Frontend Integration settings for your test environment
|
105
|
+
│ - Login redirect path: / → /api/auth/callback
|
106
|
+
│ - Logout redirect path: / → /api/auth/logout
|
107
|
+
│ - Development URL: none → http://localhost:3000
|
108
|
+
│
|
109
|
+
◆ Your test environment config needs to be updated, would you like to apply these changes now?
|
110
|
+
│ ● yes / ○ no
|
111
|
+
│
|
112
|
+
◆ Install @propelauth/nextjs now?
|
113
|
+
│ ● npm install @propelauth/nextjs (detected)
|
114
|
+
│ ○ yarn add @propelauth/nextjs
|
115
|
+
│ ○ pnpm install @propelauth/nextjs
|
116
|
+
│ ○ bun install @propelauth/nextjs
|
117
|
+
│ ○ Skip installation
|
118
|
+
│
|
119
|
+
● _app.tsx with AuthProvider at /src/pages/_app.tsx differs from what we expected.
|
120
|
+
│
|
121
|
+
◆ Overwrite _app.tsx with AuthProvider?
|
122
|
+
│ ● Yes / ○ No
|
123
|
+
│
|
124
|
+
└ PropelAuth has been successfully set up in your Next.js project!
|
125
|
+
```
|
126
|
+
|
127
|
+
Once the CLI has successfully installed PropelAuth within your Next.js project it will also include some example components to help you get started.
|
128
|
+
|
129
|
+
### App Router Server Component
|
130
|
+
|
131
|
+
```jsx {{ title: "Server Component" }}
|
132
|
+
import { getUserOrRedirect } from "@propelauth/nextjs/server/app-router";
|
150
133
|
|
151
|
-
|
152
|
-
const user = await
|
153
|
-
|
154
|
-
return { redirect: { destination: '/api/auth/login', permanent: false } }
|
155
|
-
}
|
156
|
-
return { props: { userJson: JSON.stringify(user) } }
|
134
|
+
const WelcomeMessage = async () => {
|
135
|
+
const user = await getUserOrRedirect()
|
136
|
+
return <div>Welcome, {user.email}!</div>
|
157
137
|
}
|
158
|
-
```
|
159
|
-
|
160
|
-
### Get the user in API Routes (Pages example)
|
161
138
|
|
162
|
-
|
163
|
-
import { NextApiRequest, NextApiResponse } from 'next'
|
164
|
-
import { getUserFromApiRouteRequest } from '@propelauth/nextjs/server/pages'
|
165
|
-
|
166
|
-
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
167
|
-
const user = await getUserFromApiRouteRequest(req, res)
|
168
|
-
if (user) {
|
169
|
-
res.status(200).json({ email: user.email })
|
170
|
-
} else {
|
171
|
-
res.status(401).json({ error: 'unauthorized' })
|
172
|
-
}
|
173
|
-
}
|
139
|
+
export default WelcomeMessage;
|
174
140
|
```
|
175
141
|
|
176
|
-
###
|
142
|
+
### App Router Client Component
|
177
143
|
|
178
|
-
```
|
179
|
-
|
144
|
+
```jsx
|
145
|
+
"use client";
|
180
146
|
|
181
|
-
import { useUser } from
|
147
|
+
import { useUser } from "@propelauth/nextjs/client";
|
182
148
|
|
183
149
|
const WelcomeMessage = () => {
|
184
|
-
const {
|
185
|
-
|
150
|
+
const {loading, user} = useUser()
|
186
151
|
if (loading) {
|
187
152
|
return <div>Loading...</div>
|
188
153
|
} else if (user) {
|
189
|
-
return <div>
|
154
|
+
return <div>Welcome, {user.email}!</div>
|
190
155
|
} else {
|
191
156
|
return <div>Please log in to be welcomed</div>
|
192
157
|
}
|
193
158
|
}
|
194
|
-
```
|
195
|
-
|
196
|
-
### Checking organization membership / RBAC
|
197
|
-
|
198
|
-
Note that this works on both the client's `User` object or the client/server `UserFromToken` object, but the below example is on the server.
|
199
|
-
|
200
|
-
If you are curious where the organization information comes from, check out our documentation on [organizations](https://docs.propelauth.com/overview/organizations?utm_source=github&utm_medium=library&utm_campaign=nextjs).
|
201
|
-
The quick answer is:
|
202
|
-
|
203
|
-
- PropelAuth provides UI for users to create organizations and invite other users to join them.
|
204
|
-
- Your users can also create Enterprise SSO/SAML connections to their own Identity Providers (IdPs) so their organization members can log in with their existing work credentials.
|
205
|
-
- You can create organizations and add users to them via our APIs or our Dashboard.
|
206
|
-
|
207
|
-
```tsx
|
208
|
-
// src/app/org/[slug]/page.tsx
|
209
|
-
import { getUserOrRedirect } from '@propelauth/nextjs/server/app-router'
|
210
|
-
|
211
|
-
export default async function AdminOnlyPage({ params }: { params: { slug: string } }) {
|
212
|
-
const user = await getUserOrRedirect()
|
213
|
-
const org = user.getOrgByName(params.slug)
|
214
|
-
const isAdmin = org?.isRole('Admin')
|
215
|
-
|
216
|
-
if (!isAdmin) {
|
217
|
-
return <div>Not found</div>
|
218
|
-
} else {
|
219
|
-
return (
|
220
|
-
<div>
|
221
|
-
Welcome {user.firstName}, Admin of {org?.orgName}
|
222
|
-
</div>
|
223
|
-
)
|
224
|
-
}
|
225
|
-
}
|
226
|
-
```
|
227
|
-
|
228
|
-
### Logging out
|
229
|
-
|
230
|
-
```tsx
|
231
|
-
'use client'
|
232
|
-
|
233
|
-
import { useLogoutFunction } from '@propelauth/nextjs/client'
|
234
|
-
|
235
|
-
export default function LogoutButton() {
|
236
|
-
const logoutFn = useLogoutFunction()
|
237
|
-
return <button onClick={logoutFn}>Logout</button>
|
238
|
-
}
|
239
|
-
```
|
240
|
-
|
241
|
-
### Logging in / Signing up
|
242
|
-
|
243
|
-
If you don't want to use redirect functions, you can also use `useHostedPageUrls` which will return the URLs instead of redirecting.
|
244
|
-
|
245
|
-
```tsx
|
246
|
-
'use client'
|
247
159
|
|
248
|
-
|
249
|
-
|
250
|
-
export default function SignupAndLoginButtons() {
|
251
|
-
const { redirectToSignupPage, redirectToLoginPage } = useRedirectFunctions()
|
252
|
-
return (
|
253
|
-
<>
|
254
|
-
<button onClick={redirectToSignupPage}>Sign up</button>
|
255
|
-
<button onClick={redirectToLoginPage}>Log in</button>
|
256
|
-
</>
|
257
|
-
)
|
258
|
-
}
|
160
|
+
export default WelcomeMessage;
|
259
161
|
```
|
260
162
|
|
261
|
-
|
262
|
-
|
263
|
-
PropelAuth also provides you with pre-built account and organization management UIs.
|
264
|
-
You can redirect your users to these pages by using the following functions:
|
163
|
+
## Calling Backend APIs
|
265
164
|
|
266
|
-
|
267
|
-
|
165
|
+
You can also use the library to call the PropelAuth APIs directly, allowing you to fetch users, create orgs, and a lot more.
|
166
|
+
See the [API Reference](https://docs.propelauth.com/reference) for more information.
|
268
167
|
|
269
|
-
|
270
|
-
|
271
|
-
export default function AccountAndOrgButtons() {
|
272
|
-
const { redirectToAccountPage, redirectToOrgPage } = useRedirectFunctions()
|
273
|
-
return (
|
274
|
-
<>
|
275
|
-
<button onClick={redirectToAccountPage}>Account</button>
|
276
|
-
<button onClick={redirectToOrgPage}>Organization</button>
|
277
|
-
</>
|
278
|
-
)
|
279
|
-
}
|
280
|
-
```
|
281
|
-
|
282
|
-
### Using APIs
|
283
|
-
|
284
|
-
You can use our [APIs](https://docs.propelauth.com/reference/backend-apis/node) like so:
|
285
|
-
|
286
|
-
```ts
|
287
|
-
import { getPropelAuthApis } from '@propelauth/nextjs/server'
|
168
|
+
```typescript
|
169
|
+
import { getPropelAuthApis } from "@propelauth/nextjs/server";
|
288
170
|
|
171
|
+
// Can be done in an API route or getServerSideProps
|
289
172
|
const apis = getPropelAuthApis()
|
290
173
|
await apis.disableUser(userId)
|
291
174
|
```
|
292
175
|
|
293
|
-
|
176
|
+
## Questions?
|
294
177
|
|
295
|
-
|
296
|
-
to an external API, you'll need an access token. You can get an access token on the frontend from the `useUser` hook:
|
297
|
-
|
298
|
-
```tsx
|
299
|
-
import { useUser } from '@propelauth/nextjs/client'
|
300
|
-
|
301
|
-
const MyComponent = () => {
|
302
|
-
const { loading, accessToken } = useUser()
|
303
|
-
|
304
|
-
// Make a request to an external API with useEffect, useQuery, etc.
|
305
|
-
}
|
306
|
-
```
|
178
|
+
Feel free to reach out at support@propelauth.com
|
307
179
|
|
308
|
-
Within the App Router, you can also call `getAccessToken` to get the access token.
|
package/dist/server/index.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import * as _propelauth_node_apis from '@propelauth/node-apis';
|
2
|
-
export { AccessToken, AccessTokenCreationException, AddUserToOrgException, AddUserToOrgRequest, ApiKeyCreateException, ApiKeyDeleteException, ApiKeyFetchException, ApiKeyFull, ApiKeyNew, ApiKeyResultPage, ApiKeyUpdateException, ApiKeyUpdateRequest, ApiKeyValidateException, ApiKeyValidateRateLimitedException, ApiKeyValidation, ApiKeysCreateRequest, ApiKeysQueryRequest, ChangeUserRoleInOrgException, CreateAccessTokenRequest, CreateMagicLinkRequest, CreateOrgException, CreateOrgRequest, CreateUserException, CreateUserRequest, FetchPendingInvitesParams, FetchSamlSpMetadataResponse, ForbiddenException, IdpProvider, MagicLink, MagicLinkCreationException, MigrateUserException, MigrateUserFromExternalSourceRequest, Org, OrgApiKeyValidation, OrgQuery, OrgQueryResponse, Organization, PendingInvite, PendingInvitesPage, PersonalApiKeyValidation, RateLimitedException, RemoveUserFromOrgException, RemoveUserFromOrgRequest, RevokePendingOrgInviteRequest, SetSamlIdpMetadataRequest, TokenVerificationMetadata, UnexpectedException, UpdateOrgException, UpdateOrgRequest, UpdateUserEmailException, UpdateUserEmailRequest, UpdateUserMetadataException, UpdateUserMetadataRequest, UpdateUserPasswordException, UpdateUserPasswordRequest, UserInOrgMetadata, UserNotFoundException, UsersInOrgPagedResponse, UsersInOrgQuery, UsersPagedResponse, UsersQuery } from '@propelauth/node-apis';
|
2
|
+
export { AccessToken, AccessTokenCreationException, AddUserToOrgException, AddUserToOrgRequest, ApiKeyCreateException, ApiKeyDeleteException, ApiKeyFetchException, ApiKeyFull, ApiKeyNew, ApiKeyResultPage, ApiKeyUpdateException, ApiKeyUpdateRequest, ApiKeyValidateException, ApiKeyValidateRateLimitedException, ApiKeyValidation, ApiKeysCreateRequest, ApiKeysQueryRequest, ChangeUserRoleInOrgException, CreateAccessTokenRequest, CreateMagicLinkRequest, CreateOrgException, CreateOrgRequest, CreateUserException, CreateUserRequest, FetchPendingInvitesParams, FetchSamlSpMetadataResponse, ForbiddenException, IdpProvider, MagicLink, MagicLinkCreationException, MigrateUserException, MigrateUserFromExternalSourceRequest, MigrateUserPasswordException, MigrateUserPasswordRequest, Org, OrgApiKeyValidation, OrgQuery, OrgQueryResponse, Organization, PendingInvite, PendingInvitesPage, PersonalApiKeyValidation, RateLimitedException, RemoveUserFromOrgException, RemoveUserFromOrgRequest, RevokePendingOrgInviteRequest, SetSamlIdpMetadataRequest, TokenVerificationMetadata, UnexpectedException, UpdateOrgException, UpdateOrgRequest, UpdateUserEmailException, UpdateUserEmailRequest, UpdateUserMetadataException, UpdateUserMetadataRequest, UpdateUserPasswordException, UpdateUserPasswordRequest, UserInOrgMetadata, UserNotFoundException, UsersInOrgPagedResponse, UsersInOrgQuery, UsersPagedResponse, UsersQuery } from '@propelauth/node-apis';
|
3
3
|
import { NextResponse, NextRequest } from 'next/server';
|
4
4
|
|
5
5
|
declare enum SocialLoginProvider {
|
@@ -210,6 +210,7 @@ declare const getPropelAuthApis: () => {
|
|
210
210
|
createMagicLink: (createMagicLinkRequest: _propelauth_node_apis.CreateMagicLinkRequest) => Promise<_propelauth_node_apis.MagicLink>;
|
211
211
|
createAccessToken: (createAccessTokenRequest: _propelauth_node_apis.CreateAccessTokenRequest) => Promise<_propelauth_node_apis.AccessToken>;
|
212
212
|
migrateUserFromExternalSource: (migrateUserFromExternalSourceRequest: _propelauth_node_apis.MigrateUserFromExternalSourceRequest) => Promise<_propelauth_node_apis.CreatedUser>;
|
213
|
+
migrateUserPassword: (migrateUserPasswordRequest: _propelauth_node_apis.MigrateUserPasswordRequest) => Promise<boolean>;
|
213
214
|
deleteUser: (userId: string) => Promise<boolean>;
|
214
215
|
disableUser: (userId: string) => Promise<boolean>;
|
215
216
|
enableUser: (userId: string) => Promise<boolean>;
|
package/dist/server/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/server/index.ts","../../src/loginMethod.ts","../../src/user.ts","../../src/server/exceptions.ts","../../src/server/shared.ts","../../src/server/api.ts","../../src/server/middleware/auth-hook-response.ts","../../src/shared.ts","../../src/server/app-router.ts","../../src/server/middleware/advanced-middleware.ts"],"sourcesContent":["export { validateAccessToken, validateAccessTokenOrUndefined } from './shared'\nexport type { OrgIdToOrgMemberInfo } from '../user'\nexport { UserFromToken, OrgMemberInfo } from '../user'\nexport { UnauthorizedException, ConfigurationException } from './exceptions'\nexport { getPropelAuthApis } from './api'\nexport { AuthHookResponse } from './middleware/auth-hook-response'\nexport { buildAuthMiddleware } from './middleware/advanced-middleware'\nexport type { PropelAuthMiddlewareOptions } from './middleware/advanced-middleware'\nexport type {\n AccessToken,\n AccessTokenCreationException,\n AddUserToOrgException,\n AddUserToOrgRequest,\n ApiKeyCreateException,\n ApiKeyDeleteException,\n ApiKeyFetchException,\n ApiKeyFull,\n ApiKeyNew,\n ApiKeyResultPage,\n ApiKeyUpdateException,\n ApiKeyUpdateRequest,\n ApiKeyValidateException,\n ApiKeyValidateRateLimitedException,\n ApiKeyValidation,\n ApiKeysCreateRequest,\n ApiKeysQueryRequest,\n ChangeUserRoleInOrgException,\n CreateAccessTokenRequest,\n CreateMagicLinkRequest,\n CreateOrgException,\n CreateOrgRequest,\n CreateUserException,\n CreateUserRequest,\n ForbiddenException,\n MagicLink,\n MagicLinkCreationException,\n MigrateUserException,\n MigrateUserFromExternalSourceRequest,\n Org,\n Organization,\n OrgApiKeyValidation,\n OrgQuery,\n OrgQueryResponse,\n PersonalApiKeyValidation,\n RateLimitedException,\n RemoveUserFromOrgException,\n RemoveUserFromOrgRequest,\n TokenVerificationMetadata,\n UnexpectedException,\n UpdateOrgException,\n UpdateOrgRequest,\n UpdateUserEmailException,\n UpdateUserEmailRequest,\n UpdateUserMetadataException,\n UpdateUserMetadataRequest,\n UpdateUserPasswordException,\n UpdateUserPasswordRequest,\n UserNotFoundException,\n UserInOrgMetadata,\n UsersInOrgQuery,\n UsersPagedResponse,\n UsersInOrgPagedResponse,\n UsersQuery,\n FetchPendingInvitesParams,\n PendingInvitesPage,\n PendingInvite,\n RevokePendingOrgInviteRequest,\n FetchSamlSpMetadataResponse,\n SetSamlIdpMetadataRequest,\n IdpProvider,\n} from '@propelauth/node-apis'\n","export enum SocialLoginProvider {\n Google = 'Google',\n GitHub = 'GitHub',\n Microsoft = 'Microsoft',\n Slack = 'Slack',\n LinkedIn = 'LinkedIn',\n Salesforce = 'Salesforce',\n Xero = 'Xero',\n QuickBooksOnline = 'QuickBooks Online',\n}\n\nexport enum SamlLoginProvider {\n Google = 'Google',\n Rippling = 'Rippling',\n OneLogin = 'OneLogin',\n JumpCloud = 'JumpCloud',\n Okta = 'Okta',\n Azure = 'Azure',\n Duo = 'Duo',\n Generic = 'Generic',\n}\n\ntype InternalPasswordLoginMethod = {\n login_method: 'password'\n}\n\ntype InternalMagicLinkLoginMethod = {\n login_method: 'magic_link'\n}\n\ntype InternalSocialSsoLoginMethod = {\n login_method: 'social_sso'\n provider: SocialLoginProvider\n}\n\ntype InternalEmailConfirmationLinkLoginMethod = {\n login_method: 'email_confirmation_link'\n}\n\ntype InternalSamlSsoLoginMethod = {\n login_method: 'saml_sso'\n provider: SamlLoginProvider\n org_id: string\n}\n\ntype InternalImpersonationLoginMethod = {\n login_method: 'impersonation'\n}\n\ntype InternalGeneratedFromBackendApiLoginMethod = {\n login_method: 'generated_from_backend_api'\n}\n\ntype InternalUnknownLoginMethod = {\n login_method: 'unknown'\n}\n\nexport type InternalLoginMethod =\n | InternalPasswordLoginMethod\n | InternalMagicLinkLoginMethod\n | InternalSocialSsoLoginMethod\n | InternalEmailConfirmationLinkLoginMethod\n | InternalSamlSsoLoginMethod\n | InternalImpersonationLoginMethod\n | InternalGeneratedFromBackendApiLoginMethod\n | InternalUnknownLoginMethod\n\ntype PasswordLoginMethod = {\n loginMethod: 'password'\n}\n\ntype MagicLinkLoginMethod = {\n loginMethod: 'magic_link'\n}\n\ntype SocialSsoLoginMethod = {\n loginMethod: 'social_sso'\n provider: SocialLoginProvider\n}\n\ntype EmailConfirmationLinkLoginMethod = {\n loginMethod: 'email_confirmation_link'\n}\n\ntype SamlSsoLoginMethod = {\n loginMethod: 'saml_sso'\n provider: SamlLoginProvider\n orgId: string\n}\n\ntype ImpersonationLoginMethod = {\n loginMethod: 'impersonation'\n}\n\ntype GeneratedFromBackendApiLoginMethod = {\n loginMethod: 'generated_from_backend_api'\n}\n\ntype UnknownLoginMethod = {\n loginMethod: 'unknown'\n}\n\nexport type LoginMethod =\n | PasswordLoginMethod\n | MagicLinkLoginMethod\n | SocialSsoLoginMethod\n | EmailConfirmationLinkLoginMethod\n | SamlSsoLoginMethod\n | ImpersonationLoginMethod\n | GeneratedFromBackendApiLoginMethod\n | UnknownLoginMethod\n\nexport function toLoginMethod(snake_case?: InternalLoginMethod): LoginMethod {\n if (!snake_case) {\n return { loginMethod: 'unknown' }\n }\n\n switch (snake_case.login_method) {\n case 'password':\n return { loginMethod: 'password' }\n case 'magic_link':\n return { loginMethod: 'magic_link' }\n case 'social_sso':\n return { loginMethod: 'social_sso', provider: snake_case.provider }\n case 'email_confirmation_link':\n return { loginMethod: 'email_confirmation_link' }\n case 'saml_sso':\n return { loginMethod: 'saml_sso', provider: snake_case.provider, orgId: snake_case.org_id }\n case 'impersonation':\n return { loginMethod: 'impersonation' }\n case 'generated_from_backend_api':\n return { loginMethod: 'generated_from_backend_api' }\n default:\n return { loginMethod: 'unknown' }\n }\n}\n","import { InternalLoginMethod, LoginMethod, toLoginMethod } from './loginMethod'\n\nexport class UserFromToken {\n public userId: string\n\n public activeOrgId?: string\n public orgIdToOrgMemberInfo?: OrgIdToOrgMemberInfo\n\n // Metadata about the user\n public email: string\n public firstName?: string\n public lastName?: string\n public username?: string\n public properties?: { [key: string]: unknown }\n public loginMethod?: LoginMethod\n\n // If you used our migration APIs to migrate this user from a different system,\n // this is their original ID from that system.\n public legacyUserId?: string\n public impersonatorUserId?: string\n\n constructor(\n userId: string,\n email: string,\n orgIdToOrgMemberInfo?: OrgIdToOrgMemberInfo,\n firstName?: string,\n lastName?: string,\n username?: string,\n legacyUserId?: string,\n impersonatorUserId?: string,\n properties?: { [key: string]: unknown },\n activeOrgId?: string,\n loginMethod?: LoginMethod\n ) {\n this.userId = userId\n\n this.activeOrgId = activeOrgId\n this.orgIdToOrgMemberInfo = orgIdToOrgMemberInfo\n\n this.email = email\n this.firstName = firstName\n this.lastName = lastName\n this.username = username\n\n this.legacyUserId = legacyUserId\n this.impersonatorUserId = impersonatorUserId\n\n this.properties = properties\n this.loginMethod = loginMethod\n }\n\n public getActiveOrg(): OrgMemberInfo | undefined {\n if (!this.activeOrgId || !this.orgIdToOrgMemberInfo) {\n return undefined\n }\n\n return this.orgIdToOrgMemberInfo[this.activeOrgId]\n }\n\n public getActiveOrgId(): string | undefined {\n return this.activeOrgId\n }\n\n public getOrg(orgId: string): OrgMemberInfo | undefined {\n if (!this.orgIdToOrgMemberInfo) {\n return undefined\n }\n\n return this.orgIdToOrgMemberInfo[orgId]\n }\n\n public getOrgByName(orgName: string): OrgMemberInfo | undefined {\n if (!this.orgIdToOrgMemberInfo) {\n return undefined\n }\n\n const urlSafeOrgName = orgName.toLowerCase().replace(/ /g, '-')\n for (const orgId in this.orgIdToOrgMemberInfo) {\n const orgMemberInfo = this.orgIdToOrgMemberInfo[orgId]\n if (orgMemberInfo.urlSafeOrgName === urlSafeOrgName) {\n return orgMemberInfo\n }\n }\n\n return undefined\n }\n\n public getOrgs(): OrgMemberInfo[] {\n if (!this.orgIdToOrgMemberInfo) {\n return []\n }\n\n return Object.values(this.orgIdToOrgMemberInfo)\n }\n\n public isImpersonating(): boolean {\n return !!this.impersonatorUserId\n }\n\n public static fromJSON(json: string): UserFromToken {\n const obj = JSON.parse(json)\n const orgIdToOrgMemberInfo: OrgIdToOrgMemberInfo = {}\n for (const orgId in obj.orgIdToOrgMemberInfo) {\n orgIdToOrgMemberInfo[orgId] = OrgMemberInfo.fromJSON(JSON.stringify(obj.orgIdToOrgMemberInfo[orgId]))\n }\n return new UserFromToken(\n obj.userId,\n obj.email,\n orgIdToOrgMemberInfo,\n obj.firstName,\n obj.lastName,\n obj.username,\n obj.legacyUserId,\n obj.impersonatorUserId,\n obj.properties,\n obj.activeOrgId,\n obj.loginMethod\n )\n }\n\n public static fromJwtPayload(payload: InternalUser): UserFromToken {\n let activeOrgId: string | undefined\n let orgIdToOrgMemberInfo: OrgIdToOrgMemberInfo | undefined\n\n if (payload.org_member_info) {\n activeOrgId = payload.org_member_info.org_id\n orgIdToOrgMemberInfo = toOrgIdToOrgMemberInfo({ [activeOrgId]: payload.org_member_info })\n } else {\n activeOrgId = undefined\n orgIdToOrgMemberInfo = toOrgIdToOrgMemberInfo(payload.org_id_to_org_member_info)\n }\n\n const loginMethod = toLoginMethod(payload.login_method)\n\n return new UserFromToken(\n payload.user_id,\n payload.email,\n orgIdToOrgMemberInfo,\n payload.first_name,\n payload.last_name,\n payload.username,\n payload.legacy_user_id,\n payload.impersonator_user_id,\n payload.properties,\n activeOrgId,\n loginMethod\n )\n }\n}\n\nexport type OrgIdToOrgMemberInfo = {\n [orgId: string]: OrgMemberInfo\n}\n\nexport enum OrgRoleStructure {\n SingleRole = \"single_role_in_hierarchy\",\n MultiRole = \"multi_role\",\n}\n\nexport class OrgMemberInfo {\n public orgId: string\n public orgName: string\n public orgMetadata: { [key: string]: any }\n public urlSafeOrgName: string\n public orgRoleStructure: OrgRoleStructure\n\n public userAssignedRole: string\n public userInheritedRolesPlusCurrentRole: string[]\n public userPermissions: string[]\n public userAssignedAdditionalRoles: string[]\n\n constructor(\n orgId: string,\n orgName: string,\n orgMetadata: { [key: string]: any },\n urlSafeOrgName: string,\n userAssignedRole: string,\n userInheritedRolesPlusCurrentRole: string[],\n userPermissions: string[],\n orgRoleStructure: OrgRoleStructure,\n userAssignedAdditionalRoles: string[]\n ) {\n this.orgId = orgId\n this.orgName = orgName\n this.orgMetadata = orgMetadata\n this.urlSafeOrgName = urlSafeOrgName\n this.orgRoleStructure = orgRoleStructure\n\n this.userAssignedRole = userAssignedRole\n this.userInheritedRolesPlusCurrentRole = userInheritedRolesPlusCurrentRole\n this.userPermissions = userPermissions\n this.userAssignedAdditionalRoles = userAssignedAdditionalRoles\n }\n\n // validation methods\n\n public isRole(role: string): boolean {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedRole === role || this.userAssignedAdditionalRoles.includes(role)\n } else {\n return this.userAssignedRole === role\n }\n }\n\n public isAtLeastRole(role: string): boolean {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedRole === role || this.userAssignedAdditionalRoles.includes(role)\n } else {\n return this.userInheritedRolesPlusCurrentRole.includes(role)\n }\n }\n\n public hasPermission(permission: string): boolean {\n return this.userPermissions.includes(permission)\n }\n\n public hasAllPermissions(permissions: string[]): boolean {\n return permissions.every((permission) => this.hasPermission(permission))\n }\n\n public static fromJSON(json: string): OrgMemberInfo {\n const obj = JSON.parse(json)\n return new OrgMemberInfo(\n obj.orgId,\n obj.orgName,\n obj.orgMetadata,\n obj.urlSafeOrgName,\n obj.userAssignedRole,\n obj.userInheritedRolesPlusCurrentRole,\n obj.userPermissions,\n obj.orgRoleStructure,\n obj.userAssignedAdditionalRoles\n )\n }\n\n // getters for the private fields\n\n get assignedRole(): string {\n return this.userAssignedRole\n }\n\n get assignedRoles(): string[] {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedAdditionalRoles.concat(this.userAssignedRole)\n } else {\n return [this.userAssignedRole]\n }\n }\n\n get inheritedRolesPlusCurrentRole(): string[] {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedAdditionalRoles.concat(this.userAssignedRole)\n } else {\n return this.userInheritedRolesPlusCurrentRole\n }\n }\n\n get permissions(): string[] {\n return this.userPermissions\n }\n}\n\n// These Internal types exist since the server returns snake case, but typescript/javascript\n// convention is camelCase.\nexport type InternalOrgMemberInfo = {\n org_id: string\n org_name: string\n org_metadata: { [key: string]: any }\n url_safe_org_name: string\n org_role_structure: OrgRoleStructure\n user_role: string\n inherited_user_roles_plus_current_role: string[]\n user_permissions: string[]\n additional_roles: string[]\n}\n\nexport type InternalUser = {\n user_id: string\n\n org_member_info?: InternalOrgMemberInfo\n org_id_to_org_member_info?: { [org_id: string]: InternalOrgMemberInfo }\n\n email: string\n first_name?: string\n last_name?: string\n username?: string\n properties?: { [key: string]: unknown }\n login_method?: InternalLoginMethod\n\n // If you used our migration APIs to migrate this user from a different system, this is their original ID from that system.\n legacy_user_id?: string\n impersonator_user_id?: string\n}\n\nexport function toUser(snake_case: InternalUser): UserFromToken {\n return UserFromToken.fromJwtPayload(snake_case)\n}\n\nexport function toOrgIdToOrgMemberInfo(snake_case?: {\n [org_id: string]: InternalOrgMemberInfo\n}): OrgIdToOrgMemberInfo | undefined {\n if (snake_case === undefined) {\n return undefined\n }\n const camelCase: OrgIdToOrgMemberInfo = {}\n\n for (const key of Object.keys(snake_case)) {\n const snakeCaseValue = snake_case[key]\n if (snakeCaseValue) {\n camelCase[key] = new OrgMemberInfo(\n snakeCaseValue.org_id,\n snakeCaseValue.org_name,\n snakeCaseValue.org_metadata,\n snakeCaseValue.url_safe_org_name,\n snakeCaseValue.user_role,\n snakeCaseValue.inherited_user_roles_plus_current_role,\n snakeCaseValue.user_permissions,\n snakeCaseValue.org_role_structure,\n snakeCaseValue.additional_roles\n )\n }\n }\n\n return camelCase\n}\n","export class UnauthorizedException extends Error {\n readonly message: string\n readonly status: number\n\n constructor(message: string) {\n super(message)\n this.message = message\n this.status = 401\n }\n}\n\nexport class ConfigurationException extends Error {\n readonly message: string\n readonly status: number\n\n constructor(message: string) {\n super(message)\n this.message = message\n this.status = 500\n }\n}\n","import { ResponseCookie } from 'next/dist/compiled/@edge-runtime/cookies'\nimport { InternalUser, toUser, UserFromToken } from '../user'\nimport { ConfigurationException, UnauthorizedException } from './exceptions'\nimport * as jose from 'jose'\n\ntype RefreshAndAccessTokens = {\n refreshToken: string\n accessToken: string\n error: 'none'\n}\n\ntype RefreshAndAccessTokensUnauthorizedError = {\n error: 'unauthorized'\n}\n\ntype RefreshAndAccessTokensUnexpectedError = {\n error: 'unexpected'\n}\n\nexport type RefreshTokenResponse =\n | RefreshAndAccessTokens\n | RefreshAndAccessTokensUnauthorizedError\n | RefreshAndAccessTokensUnexpectedError\n\nexport const LOGIN_PATH = '/api/auth/login'\nexport const CALLBACK_PATH = '/api/auth/callback'\nexport const USERINFO_PATH = '/api/auth/userinfo'\nexport const LOGOUT_PATH = '/api/auth/logout'\nexport const ACCESS_TOKEN_COOKIE_NAME = '__pa_at'\nexport const REFRESH_TOKEN_COOKIE_NAME = '__pa_rt'\nexport const STATE_COOKIE_NAME = '__pa_state'\nexport const CUSTOM_HEADER_FOR_ACCESS_TOKEN = 'x-propelauth-access-token'\nexport const CUSTOM_HEADER_FOR_URL = 'x-propelauth-current-url'\nexport const CUSTOM_HEADER_FOR_PATH = 'x-propelauth-current-path'\nexport const RETURN_TO_PATH_COOKIE_NAME = '__pa_return_to_path'\n\nexport const COOKIE_OPTIONS: Partial<ResponseCookie> = {\n httpOnly: true,\n secure: true,\n path: '/',\n}\n\nexport function getAuthUrlOrigin() {\n return getAuthUrl().origin\n}\n\nexport function getAuthUrl() {\n const authUrl = process.env.PROPELAUTH_AUTH_URL || process.env.NEXT_PUBLIC_AUTH_URL\n if (!authUrl) {\n throw new Error('NEXT_PUBLIC_AUTH_URL is not set')\n }\n return new URL(authUrl)\n}\n\nexport function getRedirectUri() {\n const redirectUri = process.env.PROPELAUTH_REDIRECT_URI\n if (!redirectUri) {\n throw new Error('PROPELAUTH_REDIRECT_URI is not set')\n }\n return redirectUri\n}\n\nexport function getIntegrationApiKey() {\n const integrationApiKey = process.env.PROPELAUTH_API_KEY\n if (!integrationApiKey) {\n throw new Error('PROPELAUTH_API_KEY is not set')\n }\n return integrationApiKey\n}\n\nexport function getVerifierKey() {\n const verifierKey = process.env.PROPELAUTH_VERIFIER_KEY\n if (!verifierKey) {\n throw new Error('PROPELAUTH_VERIFIER_KEY is not set')\n }\n return verifierKey.replace(/\\\\n/g, '\\n')\n}\n\nexport function getSameSiteCookieValue(): \"none\" | \"lax\" | \"strict\" {\n const sameSiteOverride = process.env.PROPELAUTH_SAME_SITE_COOKIE_OVERRIDE\n if (sameSiteOverride === 'none') {\n return 'none'\n } else if (sameSiteOverride === 'lax') {\n return 'lax'\n } else if (sameSiteOverride === 'strict') {\n return 'strict'\n } else if (sameSiteOverride) {\n throw new Error(\n 'Invalid value for PROPELAUTH_SAME_SITE_COOKIE_OVERRIDE, must be one of \"none\", \"lax\", or \"strict\"'\n )\n } else {\n return 'lax'\n }\n}\n\nexport async function refreshTokenWithAccessAndRefreshToken(\n refreshToken: string,\n activeOrgId?: string\n): Promise<RefreshTokenResponse> {\n const body = {\n refresh_token: refreshToken,\n }\n\n const queryParams = new URLSearchParams()\n if (activeOrgId) {\n queryParams.set('with_active_org_support', 'true')\n queryParams.set('active_org_id', activeOrgId)\n }\n\n const url = `${getAuthUrlOrigin()}/api/backend/v1/refresh_token?${queryParams.toString()}`\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + getIntegrationApiKey(),\n },\n })\n\n if (response.ok) {\n const data = await response.json()\n const newRefreshToken = data.refresh_token\n const { access_token: accessToken, expires_at_seconds: expiresAtSeconds } = data.access_token\n\n return {\n refreshToken: newRefreshToken,\n accessToken,\n error: 'none',\n }\n } else if (response.status === 400 || response.status === 401) {\n return { error: 'unauthorized' }\n } else {\n return { error: 'unexpected' }\n }\n}\n\nexport async function validateAccessTokenOrUndefined(\n accessToken: string | undefined\n): Promise<UserFromToken | undefined> {\n try {\n return await validateAccessToken(accessToken)\n } catch (err) {\n if (err instanceof ConfigurationException) {\n throw err\n } else if (err instanceof UnauthorizedException) {\n return undefined\n } else {\n console.info('Error validating access token', err)\n return undefined\n }\n }\n}\n\nexport async function validateAccessToken(accessToken: string | undefined): Promise<UserFromToken> {\n let publicKey\n try {\n publicKey = await jose.importSPKI(getVerifierKey(), 'RS256')\n } catch (err) {\n console.error(\"Verifier key is invalid. Make sure it's specified correctly, including the newlines.\", err)\n throw new ConfigurationException('Invalid verifier key')\n }\n\n if (!accessToken) {\n throw new UnauthorizedException('No access token provided')\n }\n\n let accessTokenWithoutBearer = accessToken\n if (accessToken.toLowerCase().startsWith('bearer ')) {\n accessTokenWithoutBearer = accessToken.substring('bearer '.length)\n }\n\n try {\n const { payload } = await jose.jwtVerify(accessTokenWithoutBearer, publicKey, {\n issuer: getAuthUrlOrigin(),\n algorithms: ['RS256'],\n })\n\n return toUser(<InternalUser>payload)\n } catch (e) {\n if (e instanceof Error) {\n throw new UnauthorizedException(e.message)\n } else {\n throw new UnauthorizedException('Unable to decode jwt')\n }\n }\n}\n","import {getApis} from \"@propelauth/node-apis\";\nimport {getAuthUrl, getIntegrationApiKey} from \"./shared\";\n\nexport const getPropelAuthApis = () => {\n const authUrl = getAuthUrl()\n const integrationApiKey = getIntegrationApiKey()\n\n return getApis(authUrl, integrationApiKey)\n}","import { NextResponse } from 'next/server'\n\nexport class AuthHookResponse {\n private constructor(\n private readonly type: 'continue' | 'reject',\n private readonly response?: NextResponse\n ) {}\n\n static continue(): AuthHookResponse {\n return new AuthHookResponse('continue')\n }\n\n static reject(response: NextResponse): AuthHookResponse {\n return new AuthHookResponse('reject', response)\n }\n\n shouldContinue(): boolean {\n return this.type === 'continue'\n }\n\n getResponse(): NextResponse | undefined {\n return this.response\n }\n}\n","export const ACTIVE_ORG_ID_COOKIE_NAME = '__pa_org_id'\n","import { redirect } from 'next/navigation'\nimport { cookies, headers } from 'next/headers'\nimport { NextRequest, NextResponse } from 'next/server'\nimport {\n ACCESS_TOKEN_COOKIE_NAME,\n CALLBACK_PATH,\n COOKIE_OPTIONS,\n CUSTOM_HEADER_FOR_ACCESS_TOKEN,\n CUSTOM_HEADER_FOR_PATH,\n CUSTOM_HEADER_FOR_URL,\n getAuthUrlOrigin,\n getIntegrationApiKey,\n getRedirectUri,\n getSameSiteCookieValue,\n LOGIN_PATH,\n LOGOUT_PATH,\n REFRESH_TOKEN_COOKIE_NAME,\n refreshTokenWithAccessAndRefreshToken,\n RETURN_TO_PATH_COOKIE_NAME,\n STATE_COOKIE_NAME,\n USERINFO_PATH,\n validateAccessToken,\n validateAccessTokenOrUndefined,\n} from './shared'\nimport { UserFromToken } from './index'\nimport { ACTIVE_ORG_ID_COOKIE_NAME } from '../shared'\nimport { buildAuthMiddleware } from './middleware/advanced-middleware'\n\nexport type RedirectOptions =\n | {\n returnToPath: string\n returnToCurrentPath?: never\n }\n | {\n returnToPath?: never\n returnToCurrentPath: boolean\n }\n\nexport async function getUserOrRedirect(redirectOptions?: RedirectOptions): Promise<UserFromToken> {\n const user = await getUser()\n if (user) {\n return user\n } else {\n await redirectToLogin(redirectOptions)\n throw new Error('Redirecting to login')\n }\n}\n\nexport async function getUser(): Promise<UserFromToken | undefined> {\n const accessToken = await getAccessTokenAsync()\n if (accessToken) {\n const user = await validateAccessTokenOrUndefined(accessToken)\n if (user) {\n return user\n }\n }\n return undefined\n}\n\nexport function getAccessToken(): string | undefined {\n return headers().get(CUSTOM_HEADER_FOR_ACCESS_TOKEN) || cookies().get(ACCESS_TOKEN_COOKIE_NAME)?.value\n}\n\nexport async function getAccessTokenAsync(): Promise<string | undefined> {\n return (\n (await headers()).get(CUSTOM_HEADER_FOR_ACCESS_TOKEN) || (await cookies()).get(ACCESS_TOKEN_COOKIE_NAME)?.value\n )\n}\n\nexport async function authMiddleware(req: NextRequest): Promise<Response> {\n return buildAuthMiddleware()(req)\n}\n\nexport function getNextResponse(request: NextRequest, newAccessToken?: string) {\n const headers = new Headers(request.headers)\n headers.set(CUSTOM_HEADER_FOR_URL, request.nextUrl.toString())\n headers.set(CUSTOM_HEADER_FOR_PATH, request.nextUrl.pathname + request.nextUrl.search)\n if (newAccessToken) {\n headers.set(CUSTOM_HEADER_FOR_ACCESS_TOKEN, newAccessToken)\n }\n return NextResponse.next({\n request: {\n headers,\n },\n })\n}\n\nexport type RouteHandlerArgs = {\n postLoginRedirectPathFn?: (req: NextRequest) => string\n getDefaultActiveOrgId?: (req: NextRequest, user: UserFromToken) => string | undefined\n}\n\nexport function getRouteHandlers(args?: RouteHandlerArgs) {\n function loginGetHandler(req: NextRequest) {\n return signupOrLoginHandler(req, false)\n }\n\n function signupGetHandler(req: NextRequest) {\n return signupOrLoginHandler(req, true)\n }\n\n function signupOrLoginHandler(req: NextRequest, isSignup: boolean) {\n const returnToPath = req.nextUrl.searchParams.get('return_to_path')\n const state = randomState()\n const redirectUri = getRedirectUri()\n const sameSite = getSameSiteCookieValue()\n\n const authorizeUrlSearchParams = req.nextUrl.searchParams\n authorizeUrlSearchParams.set('redirect_uri', redirectUri)\n authorizeUrlSearchParams.set('state', state)\n authorizeUrlSearchParams.set('signup', isSignup ? 'true' : 'false')\n const authorize_url = getAuthUrlOrigin() + '/propelauth/ssr/authorize?' + authorizeUrlSearchParams.toString()\n\n const headers = new Headers()\n headers.append('Location', authorize_url)\n headers.append('Set-Cookie', `${STATE_COOKIE_NAME}=${state}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`)\n if (returnToPath) {\n if (returnToPath.startsWith('/')) {\n headers.append(\n 'Set-Cookie',\n `${RETURN_TO_PATH_COOKIE_NAME}=${returnToPath}; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=600`\n )\n } else {\n console.warn('return_to_path must start with /')\n }\n }\n\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n\n async function callbackGetHandler(req: NextRequest) {\n const sameSite = getSameSiteCookieValue()\n const oauthState = req.cookies.get(STATE_COOKIE_NAME)?.value\n if (!oauthState || oauthState.length !== 64) {\n return new Response(null, { status: 302, headers: { Location: LOGIN_PATH } })\n }\n\n const queryParams = req.nextUrl.searchParams\n const state = queryParams.get('state')\n const code = queryParams.get('code')\n if (state !== oauthState) {\n return new Response(null, { status: 302, headers: { Location: LOGIN_PATH } })\n }\n\n const authUrlOrigin = getAuthUrlOrigin()\n const redirectUri = getRedirectUri()\n const integrationApiKey = getIntegrationApiKey()\n const oauth_token_body = {\n redirect_uri: redirectUri,\n code,\n }\n const url = `${authUrlOrigin}/propelauth/ssr/token`\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(oauth_token_body),\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + integrationApiKey,\n },\n })\n\n if (response.ok) {\n const data = await response.json()\n\n const accessToken = data.access_token\n\n // If we have a return_to_path cookie, we'll use that\n // Otherwise, we'll use the postLoginRedirectPathFn\n const returnToPathFromCookie = req.cookies.get(RETURN_TO_PATH_COOKIE_NAME)?.value\n const returnToPath =\n returnToPathFromCookie ?? (args?.postLoginRedirectPathFn ? args.postLoginRedirectPathFn(req) : '/')\n if (!returnToPath) {\n console.error('postLoginRedirectPathFn returned undefined')\n return new Response('Unexpected error', { status: 500 })\n }\n\n // For Active Org, if there is one set, we need to issue a new access token\n // We start by checking if there's an existing cookie AND the user is in that org\n // Otherwise, we'll use the default active org function to get the active org\n // If none of that, we'll just use the access token as is\n const currentActiveOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n\n const user = await validateAccessToken(accessToken)\n const isUserInCurrentActiveOrg = !!currentActiveOrgId && !!user.getOrg(currentActiveOrgId)\n\n let activeOrgId = undefined\n if (isUserInCurrentActiveOrg) {\n activeOrgId = currentActiveOrgId\n } else if (args?.getDefaultActiveOrgId) {\n activeOrgId = args.getDefaultActiveOrgId(req, user)\n }\n\n // If there's an active org, we need to re-issue a new access token for the active org\n if (activeOrgId) {\n const response = await refreshTokenWithAccessAndRefreshToken(data.refresh_token, activeOrgId)\n if (response.error === 'unexpected') {\n throw new Error('Unexpected error while setting active org')\n } else if (response.error === 'unauthorized') {\n console.error(\n 'Unauthorized error while setting active org. Your user may not have access to this org'\n )\n return new Response('Unauthorized', { status: 401 })\n } else {\n const headers = new Headers()\n headers.append('Location', returnToPath)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${response.accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${response.refreshToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=${activeOrgId}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append('Set-Cookie', getCookieForReturnToPathInCallback(returnToPathFromCookie))\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n }\n\n const headers = new Headers()\n headers.append('Location', returnToPath)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${data.refresh_token}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append('Set-Cookie', getCookieForReturnToPathInCallback(returnToPathFromCookie))\n return new Response(null, {\n status: 302,\n headers,\n })\n } else if (response.status === 401) {\n const apiKey = getIntegrationApiKey()\n const firstFourChars = apiKey.substring(0, 4)\n console.error(\n `Couldn't finish the login process for this user. This is most likely caused by an incorrect PROPELAUTH_API_KEY. Your API key starts with ${firstFourChars}... double check that that matches the API key in the PropelAuth dashboard for this environment.`\n )\n return new Response('Unexpected error', { status: 500 })\n } else {\n return new Response('Unexpected error', { status: 500 })\n }\n }\n\n async function userinfoGetHandler(req: NextRequest) {\n const oldRefreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n const activeOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n const sameSite = getSameSiteCookieValue()\n\n // For the userinfo endpoint, we want to get the most up-to-date info, so we'll refresh the access token\n if (oldRefreshToken) {\n const refreshResponse = await refreshTokenWithAccessAndRefreshToken(oldRefreshToken, activeOrgId)\n if (refreshResponse.error === 'unexpected') {\n throw new Error('Unexpected error while refreshing access token')\n } else if (refreshResponse.error === 'unauthorized') {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response('Unauthorized', { status: 401, headers })\n }\n\n const refreshToken = refreshResponse.refreshToken\n const accessToken = refreshResponse.accessToken\n\n const authUrlOrigin = getAuthUrlOrigin()\n const path = `${authUrlOrigin}/propelauth/oauth/userinfo`\n const response = await fetch(path, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + accessToken,\n },\n })\n if (response.ok) {\n const userFromToken = await validateAccessToken(accessToken)\n const data = await response.json()\n const jsonResponse = {\n userinfo: data,\n accessToken,\n impersonatorUserId: userFromToken.impersonatorUserId,\n activeOrgId,\n }\n\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${refreshToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append('Content-Type', 'application/json')\n return new Response(JSON.stringify(jsonResponse), {\n status: 200,\n headers,\n })\n } else if (response.status === 401) {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, {\n status: 401,\n headers,\n })\n } else {\n return new Response(null, { status: 500 })\n }\n }\n\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 401 })\n }\n\n async function logoutGetHandler(req: NextRequest) {\n // Real logout requests will go to the logout POST handler\n // This endpoint is a landing page for when people logout from the hosted UIs\n // Instead of doing a logout we'll check the refresh token.\n // If it's invalid, we'll clear the cookies and redirect using the postLoginRedirectPathFn\n const path = args?.postLoginRedirectPathFn ? args.postLoginRedirectPathFn(req) : '/'\n if (!path) {\n console.error('postLoginPathFn returned undefined')\n return new Response('Unexpected error', { status: 500 })\n }\n const sameSite = getSameSiteCookieValue()\n\n const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n if (!refreshToken) {\n const headers = new Headers()\n headers.append('Location', path)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n\n const activeOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n const refreshResponse = await refreshTokenWithAccessAndRefreshToken(refreshToken, activeOrgId)\n if (refreshResponse.error === 'unexpected') {\n console.error('Unexpected error while refreshing access token')\n return new Response('Unexpected error', { status: 500 })\n } else if (refreshResponse.error === 'unauthorized') {\n const headers = new Headers()\n headers.append('Location', path)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, {\n status: 302,\n headers,\n })\n } else {\n const headers = new Headers()\n headers.append('Location', path)\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n }\n\n async function logoutPostHandler(req: NextRequest) {\n const sameSite = getSameSiteCookieValue()\n const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n if (!refreshToken) {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 200, headers })\n }\n\n const authUrlOrigin = getAuthUrlOrigin()\n const integrationApiKey = getIntegrationApiKey()\n const logoutBody = { refresh_token: refreshToken }\n const url = `${authUrlOrigin}/api/backend/v1/logout`\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(logoutBody),\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + integrationApiKey,\n },\n })\n\n if (!response.ok) {\n console.warn(\n 'Unable to logout, clearing cookies and continuing anyway',\n response.status,\n response.statusText\n )\n }\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 200, headers })\n }\n\n async function setActiveOrgHandler(req: NextRequest) {\n const oldRefreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n const activeOrgId = req.nextUrl.searchParams.get('active_org_id')\n const sameSite = getSameSiteCookieValue()\n\n if (!oldRefreshToken) {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 401, headers })\n }\n\n if (!activeOrgId) {\n return new Response(null, { status: 400 })\n }\n\n const refreshResponse = await refreshTokenWithAccessAndRefreshToken(oldRefreshToken, activeOrgId)\n if (refreshResponse.error === 'unexpected') {\n throw new Error('Unexpected error while setting active org id')\n } else if (refreshResponse.error === 'unauthorized') {\n return new Response('Unauthorized', { status: 401 })\n }\n\n const refreshToken = refreshResponse.refreshToken\n const accessToken = refreshResponse.accessToken\n\n const authUrlOrigin = getAuthUrlOrigin()\n const path = `${authUrlOrigin}/propelauth/oauth/userinfo`\n const response = await fetch(path, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + accessToken,\n },\n })\n\n if (response.ok) {\n const userFromToken = await validateAccessToken(accessToken)\n const data = await response.json()\n const jsonResponse = {\n userinfo: data,\n accessToken,\n impersonatorUserId: userFromToken.impersonatorUserId,\n activeOrgId,\n }\n\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${refreshToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=${activeOrgId}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append('Content-Type', 'application/json')\n return new Response(JSON.stringify(jsonResponse), {\n status: 200,\n headers,\n })\n } else if (response.status === 401) {\n return new Response(null, {\n status: 401,\n })\n } else {\n return new Response(null, { status: 500 })\n }\n }\n\n async function getRouteHandler(req: NextRequest, { params }: { params: { slug: string } }) {\n const { slug } = await params\n if (slug === 'login') {\n return loginGetHandler(req)\n } else if (slug === 'signup') {\n return signupGetHandler(req)\n } else if (slug === 'callback') {\n return callbackGetHandler(req)\n } else if (slug === 'userinfo') {\n return userinfoGetHandler(req)\n } else if (slug === 'logout') {\n return logoutGetHandler(req)\n } else {\n return new Response('', { status: 404 })\n }\n }\n\n async function postRouteHandler(req: NextRequest, { params }: { params: { slug: string } }) {\n const { slug } = await params\n if (slug === 'logout') {\n return logoutPostHandler(req)\n } else if (slug === 'set-active-org') {\n return setActiveOrgHandler(req)\n } else {\n return new Response('', { status: 404 })\n }\n }\n\n async function getRouteHandlerAsync(req: NextRequest, { params }: { params: Promise<{ slug: string }> }) {\n const awaitedParams = await params\n return getRouteHandler(req, { params: awaitedParams })\n }\n\n async function postRouteHandlerAsync(req: NextRequest, { params }: { params: Promise<{ slug: string }> }) {\n const awaitedParams = await params\n return postRouteHandler(req, { params: awaitedParams })\n }\n\n return {\n getRouteHandler,\n postRouteHandler,\n getRouteHandlerAsync,\n postRouteHandlerAsync,\n }\n}\n\nfunction randomState(): string {\n const randomBytes = crypto.getRandomValues(new Uint8Array(32))\n return Array.from(randomBytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\nasync function redirectToLogin(redirectOptions?: RedirectOptions) {\n if (!redirectOptions) {\n redirect(LOGIN_PATH)\n } else if (redirectOptions.returnToPath) {\n const loginPath = LOGIN_PATH + '?return_to_path=' + encodeURI(redirectOptions.returnToPath)\n redirect(loginPath)\n } else if (redirectOptions.returnToCurrentPath) {\n const encodedPath = await getUrlEncodedRedirectPathForCurrentPath()\n if (encodedPath) {\n const loginPath = LOGIN_PATH + '?return_to_path=' + encodedPath\n redirect(loginPath)\n } else {\n console.warn('Could not get current URL to redirect to')\n redirect(LOGIN_PATH)\n }\n }\n}\n\nexport async function getUrlEncodedRedirectPathForCurrentPath(): Promise<string | undefined> {\n const path = await getCurrentPathAsync()\n if (!path) {\n return undefined\n }\n\n return encodeURIComponent(path)\n}\n\n// We should keep the redirect path around for a short period in case multiple windows are racing\nfunction getCookieForReturnToPathInCallback(returnToPathFromCookie: string | undefined) {\n const sameSite = getSameSiteCookieValue()\n\n if (returnToPathFromCookie) {\n return `${RETURN_TO_PATH_COOKIE_NAME}=${returnToPathFromCookie}; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=15`\n } else {\n return `${RETURN_TO_PATH_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n }\n}\n\n// It's really common to want to redirect back to the exact location you are on\n// Next.js unfortunately makes this pretty hard, as server components don't have access to the path\n// The only good way to do this is to set up some middleware and pass the path down from the middleware\n// Since we have the requirement that people set up middleware with us anyway, it's easy for us to expose\n// this functionality\nexport function getCurrentPath(): string | undefined {\n const path = headers().get(CUSTOM_HEADER_FOR_PATH)\n if (!path) {\n console.warn(\n 'Attempting to redirect to the current path, but we could not find the current path in the headers. Is the middleware set up?'\n )\n return undefined\n } else {\n return path\n }\n}\n\nexport async function getCurrentPathAsync(): Promise<string | undefined> {\n const path = (await headers()).get(CUSTOM_HEADER_FOR_PATH)\n if (!path) {\n console.warn(\n 'Attempting to redirect to the current path, but we could not find the current path in the headers. Is the middleware set up?'\n )\n return undefined\n } else {\n return path\n }\n}\n\n/**\n * @deprecated since version 0.1.0\n * Use getCurrentPath instead\n */\nexport function getCurrentUrl(): string | undefined {\n console.warn('getCurrentUrl is deprecated in favor of getCurrentPath.')\n const url = headers().get(CUSTOM_HEADER_FOR_URL)\n if (!url) {\n console.warn(\n 'Attempting to redirect to the current URL, but we could not find the current URL in the headers. Is the middleware set up?'\n )\n return undefined\n } else {\n return url\n }\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport {\n ACCESS_TOKEN_COOKIE_NAME,\n CALLBACK_PATH,\n COOKIE_OPTIONS,\n LOGOUT_PATH,\n REFRESH_TOKEN_COOKIE_NAME,\n USERINFO_PATH,\n getSameSiteCookieValue,\n refreshTokenWithAccessAndRefreshToken,\n validateAccessToken,\n validateAccessTokenOrUndefined,\n} from '../shared'\nimport { ACTIVE_ORG_ID_COOKIE_NAME } from '../../shared'\nimport { getNextResponse } from '../app-router'\nimport { UserFromToken } from '../../user'\nimport { AuthHookResponse } from './auth-hook-response'\n\nexport type PropelAuthMiddlewareOptions = {\n afterAuthHook?: (req: NextRequest, res: NextResponse, user?: UserFromToken) => Promise<AuthHookResponse>\n}\n\n// Purpose of this middleware is just to keep the access token cookie alive\n// In an ideal world, this could be done in `getUser`, however, you can't\n// set a cookie in a server component.\n// There also doesn't seem to be any way right now to set a cookie in a\n// middleware and pass it forward (you can only set them on the response).\n// You CAN, however, pass in custom headers,\n// so we'll use CUSTOM_HEADER_FOR_ACCESS_TOKEN as a workaround\nexport function buildAuthMiddleware(options?: PropelAuthMiddlewareOptions): (req: NextRequest) => Promise<Response> {\n return async (req: NextRequest) => {\n if (\n req.nextUrl.pathname === CALLBACK_PATH ||\n req.nextUrl.pathname === LOGOUT_PATH ||\n req.nextUrl.pathname === USERINFO_PATH\n ) {\n // Don't do anything for the callback, logout, or userinfo paths, as they will modify the cookies themselves\n return getNextResponse(req)\n }\n\n const accessToken = req.cookies.get(ACCESS_TOKEN_COOKIE_NAME)?.value\n const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n const activeOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n\n // If we are authenticated, we can continue\n if (accessToken) {\n const user = await validateAccessTokenOrUndefined(accessToken)\n if (user) {\n const nextResponse = getNextResponse(req)\n return await handlePostAuthHook(req, nextResponse, user, options)\n }\n }\n\n // Otherwise, we need to refresh the access token\n if (refreshToken) {\n const response = await refreshTokenWithAccessAndRefreshToken(refreshToken, activeOrgId)\n if (response.error === 'unexpected') {\n throw new Error('Unexpected error while refreshing access token')\n } else if (response.error === 'unauthorized') {\n const response = getNextResponse(req)\n response.cookies.delete(ACCESS_TOKEN_COOKIE_NAME)\n response.cookies.delete(REFRESH_TOKEN_COOKIE_NAME)\n return await handlePostAuthHook(req, response, undefined, options)\n } else {\n const sameSite = getSameSiteCookieValue()\n const nextResponse = getNextResponse(req, response.accessToken)\n nextResponse.cookies.set(ACCESS_TOKEN_COOKIE_NAME, response.accessToken, {\n ...COOKIE_OPTIONS,\n sameSite,\n })\n nextResponse.cookies.set(REFRESH_TOKEN_COOKIE_NAME, response.refreshToken, {\n ...COOKIE_OPTIONS,\n sameSite,\n })\n const user = await validateAccessToken(response.accessToken)\n return await handlePostAuthHook(req, nextResponse, user, options)\n }\n }\n\n const res = getNextResponse(req)\n return await handlePostAuthHook(req, res, undefined, options)\n }\n}\n\nconst handlePostAuthHook = async (\n req: NextRequest,\n res: NextResponse,\n user?: UserFromToken,\n options?: PropelAuthMiddlewareOptions\n): Promise<NextResponse> => {\n if (options?.afterAuthHook) {\n const hookResponse = await options.afterAuthHook(req, res, user)\n if (hookResponse instanceof AuthHookResponse) {\n if (!hookResponse.shouldContinue()) {\n return hookResponse.getResponse() ?? res\n }\n } else {\n console.warn('afterAuthHook did not return a AuthHookResponse, continuing')\n }\n }\n return res\n}\n"],"mappings":"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","names":["headers","response"]}
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts","../../src/loginMethod.ts","../../src/user.ts","../../src/server/exceptions.ts","../../src/server/shared.ts","../../src/server/api.ts","../../src/server/middleware/auth-hook-response.ts","../../src/shared.ts","../../src/server/app-router.ts","../../src/server/middleware/advanced-middleware.ts"],"sourcesContent":["export { validateAccessToken, validateAccessTokenOrUndefined } from './shared'\nexport type { OrgIdToOrgMemberInfo } from '../user'\nexport { UserFromToken, OrgMemberInfo } from '../user'\nexport { UnauthorizedException, ConfigurationException } from './exceptions'\nexport { getPropelAuthApis } from './api'\nexport { AuthHookResponse } from './middleware/auth-hook-response'\nexport { buildAuthMiddleware } from './middleware/advanced-middleware'\nexport type { PropelAuthMiddlewareOptions } from './middleware/advanced-middleware'\nexport type {\n AccessToken,\n AccessTokenCreationException,\n AddUserToOrgException,\n AddUserToOrgRequest,\n ApiKeyCreateException,\n ApiKeyDeleteException,\n ApiKeyFetchException,\n ApiKeyFull,\n ApiKeyNew,\n ApiKeyResultPage,\n ApiKeyUpdateException,\n ApiKeyUpdateRequest,\n ApiKeyValidateException,\n ApiKeyValidateRateLimitedException,\n ApiKeyValidation,\n ApiKeysCreateRequest,\n ApiKeysQueryRequest,\n ChangeUserRoleInOrgException,\n CreateAccessTokenRequest,\n CreateMagicLinkRequest,\n CreateOrgException,\n CreateOrgRequest,\n CreateUserException,\n CreateUserRequest,\n ForbiddenException,\n MagicLink,\n MagicLinkCreationException,\n MigrateUserException,\n MigrateUserFromExternalSourceRequest,\n MigrateUserPasswordException,\n MigrateUserPasswordRequest,\n Org,\n Organization,\n OrgApiKeyValidation,\n OrgQuery,\n OrgQueryResponse,\n PersonalApiKeyValidation,\n RateLimitedException,\n RemoveUserFromOrgException,\n RemoveUserFromOrgRequest,\n TokenVerificationMetadata,\n UnexpectedException,\n UpdateOrgException,\n UpdateOrgRequest,\n UpdateUserEmailException,\n UpdateUserEmailRequest,\n UpdateUserMetadataException,\n UpdateUserMetadataRequest,\n UpdateUserPasswordException,\n UpdateUserPasswordRequest,\n UserNotFoundException,\n UserInOrgMetadata,\n UsersInOrgQuery,\n UsersPagedResponse,\n UsersInOrgPagedResponse,\n UsersQuery,\n FetchPendingInvitesParams,\n PendingInvitesPage,\n PendingInvite,\n RevokePendingOrgInviteRequest,\n FetchSamlSpMetadataResponse,\n SetSamlIdpMetadataRequest,\n IdpProvider,\n} from '@propelauth/node-apis'\n","export enum SocialLoginProvider {\n Google = 'Google',\n GitHub = 'GitHub',\n Microsoft = 'Microsoft',\n Slack = 'Slack',\n LinkedIn = 'LinkedIn',\n Salesforce = 'Salesforce',\n Xero = 'Xero',\n QuickBooksOnline = 'QuickBooks Online',\n}\n\nexport enum SamlLoginProvider {\n Google = 'Google',\n Rippling = 'Rippling',\n OneLogin = 'OneLogin',\n JumpCloud = 'JumpCloud',\n Okta = 'Okta',\n Azure = 'Azure',\n Duo = 'Duo',\n Generic = 'Generic',\n}\n\ntype InternalPasswordLoginMethod = {\n login_method: 'password'\n}\n\ntype InternalMagicLinkLoginMethod = {\n login_method: 'magic_link'\n}\n\ntype InternalSocialSsoLoginMethod = {\n login_method: 'social_sso'\n provider: SocialLoginProvider\n}\n\ntype InternalEmailConfirmationLinkLoginMethod = {\n login_method: 'email_confirmation_link'\n}\n\ntype InternalSamlSsoLoginMethod = {\n login_method: 'saml_sso'\n provider: SamlLoginProvider\n org_id: string\n}\n\ntype InternalImpersonationLoginMethod = {\n login_method: 'impersonation'\n}\n\ntype InternalGeneratedFromBackendApiLoginMethod = {\n login_method: 'generated_from_backend_api'\n}\n\ntype InternalUnknownLoginMethod = {\n login_method: 'unknown'\n}\n\nexport type InternalLoginMethod =\n | InternalPasswordLoginMethod\n | InternalMagicLinkLoginMethod\n | InternalSocialSsoLoginMethod\n | InternalEmailConfirmationLinkLoginMethod\n | InternalSamlSsoLoginMethod\n | InternalImpersonationLoginMethod\n | InternalGeneratedFromBackendApiLoginMethod\n | InternalUnknownLoginMethod\n\ntype PasswordLoginMethod = {\n loginMethod: 'password'\n}\n\ntype MagicLinkLoginMethod = {\n loginMethod: 'magic_link'\n}\n\ntype SocialSsoLoginMethod = {\n loginMethod: 'social_sso'\n provider: SocialLoginProvider\n}\n\ntype EmailConfirmationLinkLoginMethod = {\n loginMethod: 'email_confirmation_link'\n}\n\ntype SamlSsoLoginMethod = {\n loginMethod: 'saml_sso'\n provider: SamlLoginProvider\n orgId: string\n}\n\ntype ImpersonationLoginMethod = {\n loginMethod: 'impersonation'\n}\n\ntype GeneratedFromBackendApiLoginMethod = {\n loginMethod: 'generated_from_backend_api'\n}\n\ntype UnknownLoginMethod = {\n loginMethod: 'unknown'\n}\n\nexport type LoginMethod =\n | PasswordLoginMethod\n | MagicLinkLoginMethod\n | SocialSsoLoginMethod\n | EmailConfirmationLinkLoginMethod\n | SamlSsoLoginMethod\n | ImpersonationLoginMethod\n | GeneratedFromBackendApiLoginMethod\n | UnknownLoginMethod\n\nexport function toLoginMethod(snake_case?: InternalLoginMethod): LoginMethod {\n if (!snake_case) {\n return { loginMethod: 'unknown' }\n }\n\n switch (snake_case.login_method) {\n case 'password':\n return { loginMethod: 'password' }\n case 'magic_link':\n return { loginMethod: 'magic_link' }\n case 'social_sso':\n return { loginMethod: 'social_sso', provider: snake_case.provider }\n case 'email_confirmation_link':\n return { loginMethod: 'email_confirmation_link' }\n case 'saml_sso':\n return { loginMethod: 'saml_sso', provider: snake_case.provider, orgId: snake_case.org_id }\n case 'impersonation':\n return { loginMethod: 'impersonation' }\n case 'generated_from_backend_api':\n return { loginMethod: 'generated_from_backend_api' }\n default:\n return { loginMethod: 'unknown' }\n }\n}\n","import { InternalLoginMethod, LoginMethod, toLoginMethod } from './loginMethod'\n\nexport class UserFromToken {\n public userId: string\n\n public activeOrgId?: string\n public orgIdToOrgMemberInfo?: OrgIdToOrgMemberInfo\n\n // Metadata about the user\n public email: string\n public firstName?: string\n public lastName?: string\n public username?: string\n public properties?: { [key: string]: unknown }\n public loginMethod?: LoginMethod\n\n // If you used our migration APIs to migrate this user from a different system,\n // this is their original ID from that system.\n public legacyUserId?: string\n public impersonatorUserId?: string\n\n constructor(\n userId: string,\n email: string,\n orgIdToOrgMemberInfo?: OrgIdToOrgMemberInfo,\n firstName?: string,\n lastName?: string,\n username?: string,\n legacyUserId?: string,\n impersonatorUserId?: string,\n properties?: { [key: string]: unknown },\n activeOrgId?: string,\n loginMethod?: LoginMethod\n ) {\n this.userId = userId\n\n this.activeOrgId = activeOrgId\n this.orgIdToOrgMemberInfo = orgIdToOrgMemberInfo\n\n this.email = email\n this.firstName = firstName\n this.lastName = lastName\n this.username = username\n\n this.legacyUserId = legacyUserId\n this.impersonatorUserId = impersonatorUserId\n\n this.properties = properties\n this.loginMethod = loginMethod\n }\n\n public getActiveOrg(): OrgMemberInfo | undefined {\n if (!this.activeOrgId || !this.orgIdToOrgMemberInfo) {\n return undefined\n }\n\n return this.orgIdToOrgMemberInfo[this.activeOrgId]\n }\n\n public getActiveOrgId(): string | undefined {\n return this.activeOrgId\n }\n\n public getOrg(orgId: string): OrgMemberInfo | undefined {\n if (!this.orgIdToOrgMemberInfo) {\n return undefined\n }\n\n return this.orgIdToOrgMemberInfo[orgId]\n }\n\n public getOrgByName(orgName: string): OrgMemberInfo | undefined {\n if (!this.orgIdToOrgMemberInfo) {\n return undefined\n }\n\n const urlSafeOrgName = orgName.toLowerCase().replace(/ /g, '-')\n for (const orgId in this.orgIdToOrgMemberInfo) {\n const orgMemberInfo = this.orgIdToOrgMemberInfo[orgId]\n if (orgMemberInfo.urlSafeOrgName === urlSafeOrgName) {\n return orgMemberInfo\n }\n }\n\n return undefined\n }\n\n public getOrgs(): OrgMemberInfo[] {\n if (!this.orgIdToOrgMemberInfo) {\n return []\n }\n\n return Object.values(this.orgIdToOrgMemberInfo)\n }\n\n public isImpersonating(): boolean {\n return !!this.impersonatorUserId\n }\n\n public static fromJSON(json: string): UserFromToken {\n const obj = JSON.parse(json)\n const orgIdToOrgMemberInfo: OrgIdToOrgMemberInfo = {}\n for (const orgId in obj.orgIdToOrgMemberInfo) {\n orgIdToOrgMemberInfo[orgId] = OrgMemberInfo.fromJSON(JSON.stringify(obj.orgIdToOrgMemberInfo[orgId]))\n }\n return new UserFromToken(\n obj.userId,\n obj.email,\n orgIdToOrgMemberInfo,\n obj.firstName,\n obj.lastName,\n obj.username,\n obj.legacyUserId,\n obj.impersonatorUserId,\n obj.properties,\n obj.activeOrgId,\n obj.loginMethod\n )\n }\n\n public static fromJwtPayload(payload: InternalUser): UserFromToken {\n let activeOrgId: string | undefined\n let orgIdToOrgMemberInfo: OrgIdToOrgMemberInfo | undefined\n\n if (payload.org_member_info) {\n activeOrgId = payload.org_member_info.org_id\n orgIdToOrgMemberInfo = toOrgIdToOrgMemberInfo({ [activeOrgId]: payload.org_member_info })\n } else {\n activeOrgId = undefined\n orgIdToOrgMemberInfo = toOrgIdToOrgMemberInfo(payload.org_id_to_org_member_info)\n }\n\n const loginMethod = toLoginMethod(payload.login_method)\n\n return new UserFromToken(\n payload.user_id,\n payload.email,\n orgIdToOrgMemberInfo,\n payload.first_name,\n payload.last_name,\n payload.username,\n payload.legacy_user_id,\n payload.impersonator_user_id,\n payload.properties,\n activeOrgId,\n loginMethod\n )\n }\n}\n\nexport type OrgIdToOrgMemberInfo = {\n [orgId: string]: OrgMemberInfo\n}\n\nexport enum OrgRoleStructure {\n SingleRole = \"single_role_in_hierarchy\",\n MultiRole = \"multi_role\",\n}\n\nexport class OrgMemberInfo {\n public orgId: string\n public orgName: string\n public orgMetadata: { [key: string]: any }\n public urlSafeOrgName: string\n public orgRoleStructure: OrgRoleStructure\n\n public userAssignedRole: string\n public userInheritedRolesPlusCurrentRole: string[]\n public userPermissions: string[]\n public userAssignedAdditionalRoles: string[]\n\n constructor(\n orgId: string,\n orgName: string,\n orgMetadata: { [key: string]: any },\n urlSafeOrgName: string,\n userAssignedRole: string,\n userInheritedRolesPlusCurrentRole: string[],\n userPermissions: string[],\n orgRoleStructure: OrgRoleStructure,\n userAssignedAdditionalRoles: string[]\n ) {\n this.orgId = orgId\n this.orgName = orgName\n this.orgMetadata = orgMetadata\n this.urlSafeOrgName = urlSafeOrgName\n this.orgRoleStructure = orgRoleStructure\n\n this.userAssignedRole = userAssignedRole\n this.userInheritedRolesPlusCurrentRole = userInheritedRolesPlusCurrentRole\n this.userPermissions = userPermissions\n this.userAssignedAdditionalRoles = userAssignedAdditionalRoles\n }\n\n // validation methods\n\n public isRole(role: string): boolean {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedRole === role || this.userAssignedAdditionalRoles.includes(role)\n } else {\n return this.userAssignedRole === role\n }\n }\n\n public isAtLeastRole(role: string): boolean {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedRole === role || this.userAssignedAdditionalRoles.includes(role)\n } else {\n return this.userInheritedRolesPlusCurrentRole.includes(role)\n }\n }\n\n public hasPermission(permission: string): boolean {\n return this.userPermissions.includes(permission)\n }\n\n public hasAllPermissions(permissions: string[]): boolean {\n return permissions.every((permission) => this.hasPermission(permission))\n }\n\n public static fromJSON(json: string): OrgMemberInfo {\n const obj = JSON.parse(json)\n return new OrgMemberInfo(\n obj.orgId,\n obj.orgName,\n obj.orgMetadata,\n obj.urlSafeOrgName,\n obj.userAssignedRole,\n obj.userInheritedRolesPlusCurrentRole,\n obj.userPermissions,\n obj.orgRoleStructure,\n obj.userAssignedAdditionalRoles\n )\n }\n\n // getters for the private fields\n\n get assignedRole(): string {\n return this.userAssignedRole\n }\n\n get assignedRoles(): string[] {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedAdditionalRoles.concat(this.userAssignedRole)\n } else {\n return [this.userAssignedRole]\n }\n }\n\n get inheritedRolesPlusCurrentRole(): string[] {\n if (this.orgRoleStructure === OrgRoleStructure.MultiRole) {\n return this.userAssignedAdditionalRoles.concat(this.userAssignedRole)\n } else {\n return this.userInheritedRolesPlusCurrentRole\n }\n }\n\n get permissions(): string[] {\n return this.userPermissions\n }\n}\n\n// These Internal types exist since the server returns snake case, but typescript/javascript\n// convention is camelCase.\nexport type InternalOrgMemberInfo = {\n org_id: string\n org_name: string\n org_metadata: { [key: string]: any }\n url_safe_org_name: string\n org_role_structure: OrgRoleStructure\n user_role: string\n inherited_user_roles_plus_current_role: string[]\n user_permissions: string[]\n additional_roles: string[]\n}\n\nexport type InternalUser = {\n user_id: string\n\n org_member_info?: InternalOrgMemberInfo\n org_id_to_org_member_info?: { [org_id: string]: InternalOrgMemberInfo }\n\n email: string\n first_name?: string\n last_name?: string\n username?: string\n properties?: { [key: string]: unknown }\n login_method?: InternalLoginMethod\n\n // If you used our migration APIs to migrate this user from a different system, this is their original ID from that system.\n legacy_user_id?: string\n impersonator_user_id?: string\n}\n\nexport function toUser(snake_case: InternalUser): UserFromToken {\n return UserFromToken.fromJwtPayload(snake_case)\n}\n\nexport function toOrgIdToOrgMemberInfo(snake_case?: {\n [org_id: string]: InternalOrgMemberInfo\n}): OrgIdToOrgMemberInfo | undefined {\n if (snake_case === undefined) {\n return undefined\n }\n const camelCase: OrgIdToOrgMemberInfo = {}\n\n for (const key of Object.keys(snake_case)) {\n const snakeCaseValue = snake_case[key]\n if (snakeCaseValue) {\n camelCase[key] = new OrgMemberInfo(\n snakeCaseValue.org_id,\n snakeCaseValue.org_name,\n snakeCaseValue.org_metadata,\n snakeCaseValue.url_safe_org_name,\n snakeCaseValue.user_role,\n snakeCaseValue.inherited_user_roles_plus_current_role,\n snakeCaseValue.user_permissions,\n snakeCaseValue.org_role_structure,\n snakeCaseValue.additional_roles\n )\n }\n }\n\n return camelCase\n}\n","export class UnauthorizedException extends Error {\n readonly message: string\n readonly status: number\n\n constructor(message: string) {\n super(message)\n this.message = message\n this.status = 401\n }\n}\n\nexport class ConfigurationException extends Error {\n readonly message: string\n readonly status: number\n\n constructor(message: string) {\n super(message)\n this.message = message\n this.status = 500\n }\n}\n","import { ResponseCookie } from 'next/dist/compiled/@edge-runtime/cookies'\nimport { InternalUser, toUser, UserFromToken } from '../user'\nimport { ConfigurationException, UnauthorizedException } from './exceptions'\nimport * as jose from 'jose'\n\ntype RefreshAndAccessTokens = {\n refreshToken: string\n accessToken: string\n error: 'none'\n}\n\ntype RefreshAndAccessTokensUnauthorizedError = {\n error: 'unauthorized'\n}\n\ntype RefreshAndAccessTokensUnexpectedError = {\n error: 'unexpected'\n}\n\nexport type RefreshTokenResponse =\n | RefreshAndAccessTokens\n | RefreshAndAccessTokensUnauthorizedError\n | RefreshAndAccessTokensUnexpectedError\n\nexport const LOGIN_PATH = '/api/auth/login'\nexport const CALLBACK_PATH = '/api/auth/callback'\nexport const USERINFO_PATH = '/api/auth/userinfo'\nexport const LOGOUT_PATH = '/api/auth/logout'\nexport const ACCESS_TOKEN_COOKIE_NAME = '__pa_at'\nexport const REFRESH_TOKEN_COOKIE_NAME = '__pa_rt'\nexport const STATE_COOKIE_NAME = '__pa_state'\nexport const CUSTOM_HEADER_FOR_ACCESS_TOKEN = 'x-propelauth-access-token'\nexport const CUSTOM_HEADER_FOR_URL = 'x-propelauth-current-url'\nexport const CUSTOM_HEADER_FOR_PATH = 'x-propelauth-current-path'\nexport const RETURN_TO_PATH_COOKIE_NAME = '__pa_return_to_path'\n\nexport const COOKIE_OPTIONS: Partial<ResponseCookie> = {\n httpOnly: true,\n secure: true,\n path: '/',\n}\n\nexport function getAuthUrlOrigin() {\n return getAuthUrl().origin\n}\n\nexport function getAuthUrl() {\n const authUrl = process.env.PROPELAUTH_AUTH_URL || process.env.NEXT_PUBLIC_AUTH_URL\n if (!authUrl) {\n throw new Error('NEXT_PUBLIC_AUTH_URL is not set')\n }\n return new URL(authUrl)\n}\n\nexport function getRedirectUri() {\n const redirectUri = process.env.PROPELAUTH_REDIRECT_URI\n if (!redirectUri) {\n throw new Error('PROPELAUTH_REDIRECT_URI is not set')\n }\n return redirectUri\n}\n\nexport function getIntegrationApiKey() {\n const integrationApiKey = process.env.PROPELAUTH_API_KEY\n if (!integrationApiKey) {\n throw new Error('PROPELAUTH_API_KEY is not set')\n }\n return integrationApiKey\n}\n\nexport function getVerifierKey() {\n const verifierKey = process.env.PROPELAUTH_VERIFIER_KEY\n if (!verifierKey) {\n throw new Error('PROPELAUTH_VERIFIER_KEY is not set')\n }\n return verifierKey.replace(/\\\\n/g, '\\n')\n}\n\nexport function getSameSiteCookieValue(): \"none\" | \"lax\" | \"strict\" {\n const sameSiteOverride = process.env.PROPELAUTH_SAME_SITE_COOKIE_OVERRIDE\n if (sameSiteOverride === 'none') {\n return 'none'\n } else if (sameSiteOverride === 'lax') {\n return 'lax'\n } else if (sameSiteOverride === 'strict') {\n return 'strict'\n } else if (sameSiteOverride) {\n throw new Error(\n 'Invalid value for PROPELAUTH_SAME_SITE_COOKIE_OVERRIDE, must be one of \"none\", \"lax\", or \"strict\"'\n )\n } else {\n return 'lax'\n }\n}\n\nexport async function refreshTokenWithAccessAndRefreshToken(\n refreshToken: string,\n activeOrgId?: string\n): Promise<RefreshTokenResponse> {\n const body = {\n refresh_token: refreshToken,\n }\n\n const queryParams = new URLSearchParams()\n if (activeOrgId) {\n queryParams.set('with_active_org_support', 'true')\n queryParams.set('active_org_id', activeOrgId)\n }\n\n const url = `${getAuthUrlOrigin()}/api/backend/v1/refresh_token?${queryParams.toString()}`\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + getIntegrationApiKey(),\n },\n })\n\n if (response.ok) {\n const data = await response.json()\n const newRefreshToken = data.refresh_token\n const { access_token: accessToken, expires_at_seconds: expiresAtSeconds } = data.access_token\n\n return {\n refreshToken: newRefreshToken,\n accessToken,\n error: 'none',\n }\n } else if (response.status === 400 || response.status === 401) {\n return { error: 'unauthorized' }\n } else {\n return { error: 'unexpected' }\n }\n}\n\nexport async function validateAccessTokenOrUndefined(\n accessToken: string | undefined\n): Promise<UserFromToken | undefined> {\n try {\n return await validateAccessToken(accessToken)\n } catch (err) {\n if (err instanceof ConfigurationException) {\n throw err\n } else if (err instanceof UnauthorizedException) {\n return undefined\n } else {\n console.info('Error validating access token', err)\n return undefined\n }\n }\n}\n\nexport async function validateAccessToken(accessToken: string | undefined): Promise<UserFromToken> {\n let publicKey\n try {\n publicKey = await jose.importSPKI(getVerifierKey(), 'RS256')\n } catch (err) {\n console.error(\"Verifier key is invalid. Make sure it's specified correctly, including the newlines.\", err)\n throw new ConfigurationException('Invalid verifier key')\n }\n\n if (!accessToken) {\n throw new UnauthorizedException('No access token provided')\n }\n\n let accessTokenWithoutBearer = accessToken\n if (accessToken.toLowerCase().startsWith('bearer ')) {\n accessTokenWithoutBearer = accessToken.substring('bearer '.length)\n }\n\n try {\n const { payload } = await jose.jwtVerify(accessTokenWithoutBearer, publicKey, {\n issuer: getAuthUrlOrigin(),\n algorithms: ['RS256'],\n })\n\n return toUser(<InternalUser>payload)\n } catch (e) {\n if (e instanceof Error) {\n throw new UnauthorizedException(e.message)\n } else {\n throw new UnauthorizedException('Unable to decode jwt')\n }\n }\n}\n","import {getApis} from \"@propelauth/node-apis\";\nimport {getAuthUrl, getIntegrationApiKey} from \"./shared\";\n\nexport const getPropelAuthApis = () => {\n const authUrl = getAuthUrl()\n const integrationApiKey = getIntegrationApiKey()\n\n return getApis(authUrl, integrationApiKey)\n}","import { NextResponse } from 'next/server'\n\nexport class AuthHookResponse {\n private constructor(\n private readonly type: 'continue' | 'reject',\n private readonly response?: NextResponse\n ) {}\n\n static continue(): AuthHookResponse {\n return new AuthHookResponse('continue')\n }\n\n static reject(response: NextResponse): AuthHookResponse {\n return new AuthHookResponse('reject', response)\n }\n\n shouldContinue(): boolean {\n return this.type === 'continue'\n }\n\n getResponse(): NextResponse | undefined {\n return this.response\n }\n}\n","export const ACTIVE_ORG_ID_COOKIE_NAME = '__pa_org_id'\n","import { redirect } from 'next/navigation'\nimport { cookies, headers } from 'next/headers'\nimport { NextRequest, NextResponse } from 'next/server'\nimport {\n ACCESS_TOKEN_COOKIE_NAME,\n CALLBACK_PATH,\n COOKIE_OPTIONS,\n CUSTOM_HEADER_FOR_ACCESS_TOKEN,\n CUSTOM_HEADER_FOR_PATH,\n CUSTOM_HEADER_FOR_URL,\n getAuthUrlOrigin,\n getIntegrationApiKey,\n getRedirectUri,\n getSameSiteCookieValue,\n LOGIN_PATH,\n LOGOUT_PATH,\n REFRESH_TOKEN_COOKIE_NAME,\n refreshTokenWithAccessAndRefreshToken,\n RETURN_TO_PATH_COOKIE_NAME,\n STATE_COOKIE_NAME,\n USERINFO_PATH,\n validateAccessToken,\n validateAccessTokenOrUndefined,\n} from './shared'\nimport { UserFromToken } from './index'\nimport { ACTIVE_ORG_ID_COOKIE_NAME } from '../shared'\nimport { buildAuthMiddleware } from './middleware/advanced-middleware'\n\nexport type RedirectOptions =\n | {\n returnToPath: string\n returnToCurrentPath?: never\n }\n | {\n returnToPath?: never\n returnToCurrentPath: boolean\n }\n\nexport async function getUserOrRedirect(redirectOptions?: RedirectOptions): Promise<UserFromToken> {\n const user = await getUser()\n if (user) {\n return user\n } else {\n await redirectToLogin(redirectOptions)\n throw new Error('Redirecting to login')\n }\n}\n\nexport async function getUser(): Promise<UserFromToken | undefined> {\n const accessToken = await getAccessTokenAsync()\n if (accessToken) {\n const user = await validateAccessTokenOrUndefined(accessToken)\n if (user) {\n return user\n }\n }\n return undefined\n}\n\nexport function getAccessToken(): string | undefined {\n return headers().get(CUSTOM_HEADER_FOR_ACCESS_TOKEN) || cookies().get(ACCESS_TOKEN_COOKIE_NAME)?.value\n}\n\nexport async function getAccessTokenAsync(): Promise<string | undefined> {\n return (\n (await headers()).get(CUSTOM_HEADER_FOR_ACCESS_TOKEN) || (await cookies()).get(ACCESS_TOKEN_COOKIE_NAME)?.value\n )\n}\n\nexport async function authMiddleware(req: NextRequest): Promise<Response> {\n return buildAuthMiddleware()(req)\n}\n\nexport function getNextResponse(request: NextRequest, newAccessToken?: string) {\n const headers = new Headers(request.headers)\n headers.set(CUSTOM_HEADER_FOR_URL, request.nextUrl.toString())\n headers.set(CUSTOM_HEADER_FOR_PATH, request.nextUrl.pathname + request.nextUrl.search)\n if (newAccessToken) {\n headers.set(CUSTOM_HEADER_FOR_ACCESS_TOKEN, newAccessToken)\n }\n return NextResponse.next({\n request: {\n headers,\n },\n })\n}\n\nexport type RouteHandlerArgs = {\n postLoginRedirectPathFn?: (req: NextRequest) => string\n getDefaultActiveOrgId?: (req: NextRequest, user: UserFromToken) => string | undefined\n}\n\nexport function getRouteHandlers(args?: RouteHandlerArgs) {\n function loginGetHandler(req: NextRequest) {\n return signupOrLoginHandler(req, false)\n }\n\n function signupGetHandler(req: NextRequest) {\n return signupOrLoginHandler(req, true)\n }\n\n function signupOrLoginHandler(req: NextRequest, isSignup: boolean) {\n const returnToPath = req.nextUrl.searchParams.get('return_to_path')\n const state = randomState()\n const redirectUri = getRedirectUri()\n const sameSite = getSameSiteCookieValue()\n\n const authorizeUrlSearchParams = req.nextUrl.searchParams\n authorizeUrlSearchParams.set('redirect_uri', redirectUri)\n authorizeUrlSearchParams.set('state', state)\n authorizeUrlSearchParams.set('signup', isSignup ? 'true' : 'false')\n const authorize_url = getAuthUrlOrigin() + '/propelauth/ssr/authorize?' + authorizeUrlSearchParams.toString()\n\n const headers = new Headers()\n headers.append('Location', authorize_url)\n headers.append('Set-Cookie', `${STATE_COOKIE_NAME}=${state}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`)\n if (returnToPath) {\n if (returnToPath.startsWith('/')) {\n headers.append(\n 'Set-Cookie',\n `${RETURN_TO_PATH_COOKIE_NAME}=${returnToPath}; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=600`\n )\n } else {\n console.warn('return_to_path must start with /')\n }\n }\n\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n\n async function callbackGetHandler(req: NextRequest) {\n const sameSite = getSameSiteCookieValue()\n const oauthState = req.cookies.get(STATE_COOKIE_NAME)?.value\n if (!oauthState || oauthState.length !== 64) {\n return new Response(null, { status: 302, headers: { Location: LOGIN_PATH } })\n }\n\n const queryParams = req.nextUrl.searchParams\n const state = queryParams.get('state')\n const code = queryParams.get('code')\n if (state !== oauthState) {\n return new Response(null, { status: 302, headers: { Location: LOGIN_PATH } })\n }\n\n const authUrlOrigin = getAuthUrlOrigin()\n const redirectUri = getRedirectUri()\n const integrationApiKey = getIntegrationApiKey()\n const oauth_token_body = {\n redirect_uri: redirectUri,\n code,\n }\n const url = `${authUrlOrigin}/propelauth/ssr/token`\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(oauth_token_body),\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + integrationApiKey,\n },\n })\n\n if (response.ok) {\n const data = await response.json()\n\n const accessToken = data.access_token\n\n // If we have a return_to_path cookie, we'll use that\n // Otherwise, we'll use the postLoginRedirectPathFn\n const returnToPathFromCookie = req.cookies.get(RETURN_TO_PATH_COOKIE_NAME)?.value\n const returnToPath =\n returnToPathFromCookie ?? (args?.postLoginRedirectPathFn ? args.postLoginRedirectPathFn(req) : '/')\n if (!returnToPath) {\n console.error('postLoginRedirectPathFn returned undefined')\n return new Response('Unexpected error', { status: 500 })\n }\n\n // For Active Org, if there is one set, we need to issue a new access token\n // We start by checking if there's an existing cookie AND the user is in that org\n // Otherwise, we'll use the default active org function to get the active org\n // If none of that, we'll just use the access token as is\n const currentActiveOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n\n const user = await validateAccessToken(accessToken)\n const isUserInCurrentActiveOrg = !!currentActiveOrgId && !!user.getOrg(currentActiveOrgId)\n\n let activeOrgId = undefined\n if (isUserInCurrentActiveOrg) {\n activeOrgId = currentActiveOrgId\n } else if (args?.getDefaultActiveOrgId) {\n activeOrgId = args.getDefaultActiveOrgId(req, user)\n }\n\n // If there's an active org, we need to re-issue a new access token for the active org\n if (activeOrgId) {\n const response = await refreshTokenWithAccessAndRefreshToken(data.refresh_token, activeOrgId)\n if (response.error === 'unexpected') {\n throw new Error('Unexpected error while setting active org')\n } else if (response.error === 'unauthorized') {\n console.error(\n 'Unauthorized error while setting active org. Your user may not have access to this org'\n )\n return new Response('Unauthorized', { status: 401 })\n } else {\n const headers = new Headers()\n headers.append('Location', returnToPath)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${response.accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${response.refreshToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=${activeOrgId}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append('Set-Cookie', getCookieForReturnToPathInCallback(returnToPathFromCookie))\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n }\n\n const headers = new Headers()\n headers.append('Location', returnToPath)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${data.refresh_token}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append('Set-Cookie', getCookieForReturnToPathInCallback(returnToPathFromCookie))\n return new Response(null, {\n status: 302,\n headers,\n })\n } else if (response.status === 401) {\n const apiKey = getIntegrationApiKey()\n const firstFourChars = apiKey.substring(0, 4)\n console.error(\n `Couldn't finish the login process for this user. This is most likely caused by an incorrect PROPELAUTH_API_KEY. Your API key starts with ${firstFourChars}... double check that that matches the API key in the PropelAuth dashboard for this environment.`\n )\n return new Response('Unexpected error', { status: 500 })\n } else {\n return new Response('Unexpected error', { status: 500 })\n }\n }\n\n async function userinfoGetHandler(req: NextRequest) {\n const oldRefreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n const activeOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n const sameSite = getSameSiteCookieValue()\n\n // For the userinfo endpoint, we want to get the most up-to-date info, so we'll refresh the access token\n if (oldRefreshToken) {\n const refreshResponse = await refreshTokenWithAccessAndRefreshToken(oldRefreshToken, activeOrgId)\n if (refreshResponse.error === 'unexpected') {\n throw new Error('Unexpected error while refreshing access token')\n } else if (refreshResponse.error === 'unauthorized') {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response('Unauthorized', { status: 401, headers })\n }\n\n const refreshToken = refreshResponse.refreshToken\n const accessToken = refreshResponse.accessToken\n\n const authUrlOrigin = getAuthUrlOrigin()\n const path = `${authUrlOrigin}/propelauth/oauth/userinfo`\n const response = await fetch(path, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + accessToken,\n },\n })\n if (response.ok) {\n const userFromToken = await validateAccessToken(accessToken)\n const data = await response.json()\n const jsonResponse = {\n userinfo: data,\n accessToken,\n impersonatorUserId: userFromToken.impersonatorUserId,\n activeOrgId,\n }\n\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${refreshToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append('Content-Type', 'application/json')\n return new Response(JSON.stringify(jsonResponse), {\n status: 200,\n headers,\n })\n } else if (response.status === 401) {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, {\n status: 401,\n headers,\n })\n } else {\n return new Response(null, { status: 500 })\n }\n }\n\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 401 })\n }\n\n async function logoutGetHandler(req: NextRequest) {\n // Real logout requests will go to the logout POST handler\n // This endpoint is a landing page for when people logout from the hosted UIs\n // Instead of doing a logout we'll check the refresh token.\n // If it's invalid, we'll clear the cookies and redirect using the postLoginRedirectPathFn\n const path = args?.postLoginRedirectPathFn ? args.postLoginRedirectPathFn(req) : '/'\n if (!path) {\n console.error('postLoginPathFn returned undefined')\n return new Response('Unexpected error', { status: 500 })\n }\n const sameSite = getSameSiteCookieValue()\n\n const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n if (!refreshToken) {\n const headers = new Headers()\n headers.append('Location', path)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n\n const activeOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n const refreshResponse = await refreshTokenWithAccessAndRefreshToken(refreshToken, activeOrgId)\n if (refreshResponse.error === 'unexpected') {\n console.error('Unexpected error while refreshing access token')\n return new Response('Unexpected error', { status: 500 })\n } else if (refreshResponse.error === 'unauthorized') {\n const headers = new Headers()\n headers.append('Location', path)\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, {\n status: 302,\n headers,\n })\n } else {\n const headers = new Headers()\n headers.append('Location', path)\n return new Response(null, {\n status: 302,\n headers,\n })\n }\n }\n\n async function logoutPostHandler(req: NextRequest) {\n const sameSite = getSameSiteCookieValue()\n const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n if (!refreshToken) {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 200, headers })\n }\n\n const authUrlOrigin = getAuthUrlOrigin()\n const integrationApiKey = getIntegrationApiKey()\n const logoutBody = { refresh_token: refreshToken }\n const url = `${authUrlOrigin}/api/backend/v1/logout`\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(logoutBody),\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + integrationApiKey,\n },\n })\n\n if (!response.ok) {\n console.warn(\n 'Unable to logout, clearing cookies and continuing anyway',\n response.status,\n response.statusText\n )\n }\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 200, headers })\n }\n\n async function setActiveOrgHandler(req: NextRequest) {\n const oldRefreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n const activeOrgId = req.nextUrl.searchParams.get('active_org_id')\n const sameSite = getSameSiteCookieValue()\n\n if (!oldRefreshToken) {\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n )\n return new Response(null, { status: 401, headers })\n }\n\n if (!activeOrgId) {\n return new Response(null, { status: 400 })\n }\n\n const refreshResponse = await refreshTokenWithAccessAndRefreshToken(oldRefreshToken, activeOrgId)\n if (refreshResponse.error === 'unexpected') {\n throw new Error('Unexpected error while setting active org id')\n } else if (refreshResponse.error === 'unauthorized') {\n return new Response('Unauthorized', { status: 401 })\n }\n\n const refreshToken = refreshResponse.refreshToken\n const accessToken = refreshResponse.accessToken\n\n const authUrlOrigin = getAuthUrlOrigin()\n const path = `${authUrlOrigin}/propelauth/oauth/userinfo`\n const response = await fetch(path, {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Bearer ' + accessToken,\n },\n })\n\n if (response.ok) {\n const userFromToken = await validateAccessToken(accessToken)\n const data = await response.json()\n const jsonResponse = {\n userinfo: data,\n accessToken,\n impersonatorUserId: userFromToken.impersonatorUserId,\n activeOrgId,\n }\n\n const headers = new Headers()\n headers.append(\n 'Set-Cookie',\n `${ACCESS_TOKEN_COOKIE_NAME}=${accessToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${REFRESH_TOKEN_COOKIE_NAME}=${refreshToken}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append(\n 'Set-Cookie',\n `${ACTIVE_ORG_ID_COOKIE_NAME}=${activeOrgId}; Path=/; HttpOnly; Secure; SameSite=${sameSite}`\n )\n headers.append('Content-Type', 'application/json')\n return new Response(JSON.stringify(jsonResponse), {\n status: 200,\n headers,\n })\n } else if (response.status === 401) {\n return new Response(null, {\n status: 401,\n })\n } else {\n return new Response(null, { status: 500 })\n }\n }\n\n async function getRouteHandler(req: NextRequest, { params }: { params: { slug: string } }) {\n const { slug } = await params\n if (slug === 'login') {\n return loginGetHandler(req)\n } else if (slug === 'signup') {\n return signupGetHandler(req)\n } else if (slug === 'callback') {\n return callbackGetHandler(req)\n } else if (slug === 'userinfo') {\n return userinfoGetHandler(req)\n } else if (slug === 'logout') {\n return logoutGetHandler(req)\n } else {\n return new Response('', { status: 404 })\n }\n }\n\n async function postRouteHandler(req: NextRequest, { params }: { params: { slug: string } }) {\n const { slug } = await params\n if (slug === 'logout') {\n return logoutPostHandler(req)\n } else if (slug === 'set-active-org') {\n return setActiveOrgHandler(req)\n } else {\n return new Response('', { status: 404 })\n }\n }\n\n async function getRouteHandlerAsync(req: NextRequest, { params }: { params: Promise<{ slug: string }> }) {\n const awaitedParams = await params\n return getRouteHandler(req, { params: awaitedParams })\n }\n\n async function postRouteHandlerAsync(req: NextRequest, { params }: { params: Promise<{ slug: string }> }) {\n const awaitedParams = await params\n return postRouteHandler(req, { params: awaitedParams })\n }\n\n return {\n getRouteHandler,\n postRouteHandler,\n getRouteHandlerAsync,\n postRouteHandlerAsync,\n }\n}\n\nfunction randomState(): string {\n const randomBytes = crypto.getRandomValues(new Uint8Array(32))\n return Array.from(randomBytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\nasync function redirectToLogin(redirectOptions?: RedirectOptions) {\n if (!redirectOptions) {\n redirect(LOGIN_PATH)\n } else if (redirectOptions.returnToPath) {\n const loginPath = LOGIN_PATH + '?return_to_path=' + encodeURI(redirectOptions.returnToPath)\n redirect(loginPath)\n } else if (redirectOptions.returnToCurrentPath) {\n const encodedPath = await getUrlEncodedRedirectPathForCurrentPath()\n if (encodedPath) {\n const loginPath = LOGIN_PATH + '?return_to_path=' + encodedPath\n redirect(loginPath)\n } else {\n console.warn('Could not get current URL to redirect to')\n redirect(LOGIN_PATH)\n }\n }\n}\n\nexport async function getUrlEncodedRedirectPathForCurrentPath(): Promise<string | undefined> {\n const path = await getCurrentPathAsync()\n if (!path) {\n return undefined\n }\n\n return encodeURIComponent(path)\n}\n\n// We should keep the redirect path around for a short period in case multiple windows are racing\nfunction getCookieForReturnToPathInCallback(returnToPathFromCookie: string | undefined) {\n const sameSite = getSameSiteCookieValue()\n\n if (returnToPathFromCookie) {\n return `${RETURN_TO_PATH_COOKIE_NAME}=${returnToPathFromCookie}; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=15`\n } else {\n return `${RETURN_TO_PATH_COOKIE_NAME}=; Path=/; HttpOnly; Secure; SameSite=${sameSite}; Max-Age=0`\n }\n}\n\n// It's really common to want to redirect back to the exact location you are on\n// Next.js unfortunately makes this pretty hard, as server components don't have access to the path\n// The only good way to do this is to set up some middleware and pass the path down from the middleware\n// Since we have the requirement that people set up middleware with us anyway, it's easy for us to expose\n// this functionality\nexport function getCurrentPath(): string | undefined {\n const path = headers().get(CUSTOM_HEADER_FOR_PATH)\n if (!path) {\n console.warn(\n 'Attempting to redirect to the current path, but we could not find the current path in the headers. Is the middleware set up?'\n )\n return undefined\n } else {\n return path\n }\n}\n\nexport async function getCurrentPathAsync(): Promise<string | undefined> {\n const path = (await headers()).get(CUSTOM_HEADER_FOR_PATH)\n if (!path) {\n console.warn(\n 'Attempting to redirect to the current path, but we could not find the current path in the headers. Is the middleware set up?'\n )\n return undefined\n } else {\n return path\n }\n}\n\n/**\n * @deprecated since version 0.1.0\n * Use getCurrentPath instead\n */\nexport function getCurrentUrl(): string | undefined {\n console.warn('getCurrentUrl is deprecated in favor of getCurrentPath.')\n const url = headers().get(CUSTOM_HEADER_FOR_URL)\n if (!url) {\n console.warn(\n 'Attempting to redirect to the current URL, but we could not find the current URL in the headers. Is the middleware set up?'\n )\n return undefined\n } else {\n return url\n }\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport {\n ACCESS_TOKEN_COOKIE_NAME,\n CALLBACK_PATH,\n COOKIE_OPTIONS,\n LOGOUT_PATH,\n REFRESH_TOKEN_COOKIE_NAME,\n USERINFO_PATH,\n getSameSiteCookieValue,\n refreshTokenWithAccessAndRefreshToken,\n validateAccessToken,\n validateAccessTokenOrUndefined,\n} from '../shared'\nimport { ACTIVE_ORG_ID_COOKIE_NAME } from '../../shared'\nimport { getNextResponse } from '../app-router'\nimport { UserFromToken } from '../../user'\nimport { AuthHookResponse } from './auth-hook-response'\n\nexport type PropelAuthMiddlewareOptions = {\n afterAuthHook?: (req: NextRequest, res: NextResponse, user?: UserFromToken) => Promise<AuthHookResponse>\n}\n\n// Purpose of this middleware is just to keep the access token cookie alive\n// In an ideal world, this could be done in `getUser`, however, you can't\n// set a cookie in a server component.\n// There also doesn't seem to be any way right now to set a cookie in a\n// middleware and pass it forward (you can only set them on the response).\n// You CAN, however, pass in custom headers,\n// so we'll use CUSTOM_HEADER_FOR_ACCESS_TOKEN as a workaround\nexport function buildAuthMiddleware(options?: PropelAuthMiddlewareOptions): (req: NextRequest) => Promise<Response> {\n return async (req: NextRequest) => {\n if (\n req.nextUrl.pathname === CALLBACK_PATH ||\n req.nextUrl.pathname === LOGOUT_PATH ||\n req.nextUrl.pathname === USERINFO_PATH\n ) {\n // Don't do anything for the callback, logout, or userinfo paths, as they will modify the cookies themselves\n return getNextResponse(req)\n }\n\n const accessToken = req.cookies.get(ACCESS_TOKEN_COOKIE_NAME)?.value\n const refreshToken = req.cookies.get(REFRESH_TOKEN_COOKIE_NAME)?.value\n const activeOrgId = req.cookies.get(ACTIVE_ORG_ID_COOKIE_NAME)?.value\n\n // If we are authenticated, we can continue\n if (accessToken) {\n const user = await validateAccessTokenOrUndefined(accessToken)\n if (user) {\n const nextResponse = getNextResponse(req)\n return await handlePostAuthHook(req, nextResponse, user, options)\n }\n }\n\n // Otherwise, we need to refresh the access token\n if (refreshToken) {\n const response = await refreshTokenWithAccessAndRefreshToken(refreshToken, activeOrgId)\n if (response.error === 'unexpected') {\n throw new Error('Unexpected error while refreshing access token')\n } else if (response.error === 'unauthorized') {\n const response = getNextResponse(req)\n response.cookies.delete(ACCESS_TOKEN_COOKIE_NAME)\n response.cookies.delete(REFRESH_TOKEN_COOKIE_NAME)\n return await handlePostAuthHook(req, response, undefined, options)\n } else {\n const sameSite = getSameSiteCookieValue()\n const nextResponse = getNextResponse(req, response.accessToken)\n nextResponse.cookies.set(ACCESS_TOKEN_COOKIE_NAME, response.accessToken, {\n ...COOKIE_OPTIONS,\n sameSite,\n })\n nextResponse.cookies.set(REFRESH_TOKEN_COOKIE_NAME, response.refreshToken, {\n ...COOKIE_OPTIONS,\n sameSite,\n })\n const user = await validateAccessToken(response.accessToken)\n return await handlePostAuthHook(req, nextResponse, user, options)\n }\n }\n\n const res = getNextResponse(req)\n return await handlePostAuthHook(req, res, undefined, options)\n }\n}\n\nconst handlePostAuthHook = async (\n req: NextRequest,\n res: NextResponse,\n user?: UserFromToken,\n options?: PropelAuthMiddlewareOptions\n): Promise<NextResponse> => {\n if (options?.afterAuthHook) {\n const hookResponse = await options.afterAuthHook(req, res, user)\n if (hookResponse instanceof AuthHookResponse) {\n if (!hookResponse.shouldContinue()) {\n return hookResponse.getResponse() ?? res\n }\n } else {\n console.warn('afterAuthHook did not return a AuthHookResponse, continuing')\n }\n }\n return res\n}\n"],"mappings":"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","names":["headers","response"]}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@propelauth/nextjs",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.11",
|
4
4
|
"exports": {
|
5
5
|
"./server": {
|
6
6
|
"browser": "./dist/server/index.mjs",
|
@@ -68,7 +68,7 @@
|
|
68
68
|
"react": "^18.2.0 || ^19.0.0"
|
69
69
|
},
|
70
70
|
"dependencies": {
|
71
|
-
"@propelauth/node-apis": "^2.1.
|
71
|
+
"@propelauth/node-apis": "^2.1.32",
|
72
72
|
"jose": "^5.10.0"
|
73
73
|
}
|
74
74
|
}
|