@authgear/nextjs 0.3.0 → 0.4.0
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 +8 -1
- package/dist/{chunk-CCQOLKXU.js → chunk-AJJAXXPI.js} +1 -1
- package/dist/chunk-AJJAXXPI.js.map +1 -0
- package/dist/{chunk-UERNRN5J.js → chunk-LPGVCNZ6.js} +2 -2
- package/dist/client.d.ts +17 -4
- package/dist/client.js +39 -7
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +49 -5
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +1 -1
- package/dist/proxy.js +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/{types-Cx-gnfE7.d.ts → types-D6m4Hact.d.ts} +3 -1
- package/package.json +1 -1
- package/dist/chunk-CCQOLKXU.js.map +0 -1
- /package/dist/{chunk-UERNRN5J.js.map → chunk-LPGVCNZ6.js.map} +0 -0
package/README.md
CHANGED
|
@@ -218,10 +218,17 @@ export async function callMyApiAction() {
|
|
|
218
218
|
| Export | Description |
|
|
219
219
|
|---|---|
|
|
220
220
|
| `<AuthgearProvider>` | React context provider, must wrap the app |
|
|
221
|
-
| `useAuthgear()` | Returns `{ state, user, isLoaded, isAuthenticated, signIn, signOut }` |
|
|
221
|
+
| `useAuthgear()` | Returns `{ state, user, isLoaded, isAuthenticated, signIn, signOut, openPage }` |
|
|
222
222
|
| `useUser()` | Returns `UserInfo \| null` |
|
|
223
223
|
| `<SignInButton>` | Button that calls `signIn()` on click |
|
|
224
224
|
| `<SignOutButton>` | Button that calls `signOut()` on click |
|
|
225
|
+
| `<UserSettingsButton>` | Button that opens Authgear account settings in a new tab |
|
|
226
|
+
|
|
227
|
+
**`AuthgearProvider` props**:
|
|
228
|
+
|
|
229
|
+
| Prop | Default | Description |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| `openPagePath` | `"/api/auth/open"` | Route used by `openPage()` and `<UserSettingsButton>` to pre-authenticate and redirect to an Authgear page |
|
|
225
232
|
|
|
226
233
|
### `SignInOptions`
|
|
227
234
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export interface AuthgearConfig {\n /** Authgear endpoint, e.g. \"https://myapp.authgear.cloud\" */\n endpoint: string;\n /** OAuth client ID */\n clientID: string;\n /** Redirect URI for OAuth callback, e.g. \"http://localhost:3000/api/auth/callback\" */\n redirectURI: string;\n /** Where to redirect after logout */\n postLogoutRedirectURI?: string;\n /** OAuth scopes. Defaults to [\"openid\", \"offline_access\", \"https://authgear.com/scopes/full-userinfo\"] */\n scopes?: string[];\n /** Secret key for encrypting session cookie (min 32 chars) */\n sessionSecret: string;\n /** Session cookie name. Defaults to \"authgear.session\" */\n cookieName?: string;\n /**\n * Whether to enable SSO (Single Sign-On) with other apps on the same Authgear tenant.\n * When `true` (default), Authgear silently reuses its server-side session if the user\n * is already logged in, so users are not prompted for credentials again.\n * Set to `false` to always show the login form (`prompt=login`), which is recommended\n * for single-app deployments where silent sign-in feels unexpected to the user.\n * Defaults to `true`.\n */\n isSSOEnabled?: boolean;\n}\n\n/**\n * Pages that can be opened in a new tab with the current user pre-authenticated.\n * Used by `getOpenURL` from `@authgear/nextjs/server` and by `openPage` / `<UserSettingsButton>`\n * from `@authgear/nextjs/client`.\n */\nexport enum Page {\n Settings = \"/settings\",\n}\n\n/**\n * OIDC `prompt` parameter values.\n * Pass to `signIn({ prompt })` or `SignInButton signInOptions={{ prompt }}` to control\n * whether Authgear shows the login form for a specific authentication call.\n *\n * @see https://docs.authgear.com/authentication-and-access/single-sign-on/force-authgear-to-show-login-page\n */\nexport enum PromptOption {\n /** Always show the login form, even if the user has an active Authgear session. */\n Login = \"login\",\n /** Never show the login form; return an error if the user is not already authenticated. */\n None = \"none\",\n}\n\nexport const DEFAULT_SCOPES = [\n \"openid\",\n \"offline_access\",\n \"https://authgear.com/scopes/full-userinfo\",\n];\n\nexport enum SessionState {\n Unknown = \"UNKNOWN\",\n NoSession = \"NO_SESSION\",\n Authenticated = \"AUTHENTICATED\",\n}\n\nexport interface SessionData {\n accessToken: string;\n refreshToken: string | null;\n idToken: string | null;\n expiresAt: number;\n}\n\nexport interface Session {\n state: SessionState;\n accessToken: string | null;\n refreshToken: string | null;\n idToken: string | null;\n expiresAt: number | null;\n user: UserInfo | null;\n}\n\nexport interface UserInfo {\n sub: string;\n email?: string;\n emailVerified?: boolean;\n phoneNumber?: string;\n phoneNumberVerified?: boolean;\n preferredUsername?: string;\n givenName?: string;\n familyName?: string;\n name?: string;\n picture?: string;\n roles?: string[];\n isAnonymous?: boolean;\n isVerified?: boolean;\n canReauthenticate?: boolean;\n customAttributes?: Record<string, unknown>;\n raw: Record<string, unknown>;\n}\n\nexport interface JWTPayload {\n sub: string;\n iss: string;\n aud: string | string[];\n exp: number;\n iat: number;\n jti?: string;\n client_id?: string;\n \"https://authgear.com/claims/user/is_anonymous\"?: boolean;\n \"https://authgear.com/claims/user/is_verified\"?: boolean;\n \"https://authgear.com/claims/user/can_reauthenticate\"?: boolean;\n \"https://authgear.com/claims/user/roles\"?: string[];\n [key: string]: unknown;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n id_token?: string;\n}\n\nexport interface AppSessionTokenResponse {\n app_session_token: string;\n expire_at: string;\n}\n\nexport interface OIDCConfiguration {\n authorization_endpoint: string;\n token_endpoint: string;\n userinfo_endpoint: string;\n revocation_endpoint: string;\n end_session_endpoint: string;\n jwks_uri: string;\n issuer: string;\n}\n"],"mappings":";AA+BO,IAAK,OAAL,kBAAKA,UAAL;AACL,EAAAA,MAAA,cAAW;AADD,SAAAA;AAAA,GAAA;AAWL,IAAK,eAAL,kBAAKC,kBAAL;AAEL,EAAAA,cAAA,WAAQ;AAER,EAAAA,cAAA,UAAO;AAJG,SAAAA;AAAA,GAAA;AAOL,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAK,eAAL,kBAAKC,kBAAL;AACL,EAAAA,cAAA,aAAU;AACV,EAAAA,cAAA,eAAY;AACZ,EAAAA,cAAA,mBAAgB;AAHN,SAAAA;AAAA,GAAA;","names":["Page","PromptOption","SessionState"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_SCOPES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-AJJAXXPI.js";
|
|
4
4
|
|
|
5
5
|
// src/config.ts
|
|
6
6
|
function resolveConfig(config) {
|
|
@@ -232,4 +232,4 @@ export {
|
|
|
232
232
|
deriveSessionState,
|
|
233
233
|
isTokenExpired
|
|
234
234
|
};
|
|
235
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-LPGVCNZ6.js.map
|
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode, ButtonHTMLAttributes } from 'react';
|
|
3
|
-
import { c as SessionState, U as UserInfo } from './types-
|
|
4
|
-
export { a as PromptOption, S as Session } from './types-
|
|
3
|
+
import { c as SessionState, U as UserInfo } from './types-D6m4Hact.js';
|
|
4
|
+
export { P as Page, a as PromptOption, S as Session } from './types-D6m4Hact.js';
|
|
5
5
|
|
|
6
6
|
interface SignInOptions {
|
|
7
7
|
returnTo?: string;
|
|
@@ -21,8 +21,10 @@ interface AuthgearProviderProps {
|
|
|
21
21
|
loginPath?: string;
|
|
22
22
|
/** Path to the logout route. Defaults to "/api/auth/logout". */
|
|
23
23
|
logoutPath?: string;
|
|
24
|
+
/** Path to the open-page route handler. Defaults to "/api/auth/open". */
|
|
25
|
+
openPagePath?: string;
|
|
24
26
|
}
|
|
25
|
-
declare function AuthgearProvider({ children, userInfoPath, loginPath, logoutPath, }: AuthgearProviderProps): react_jsx_runtime.JSX.Element;
|
|
27
|
+
declare function AuthgearProvider({ children, userInfoPath, loginPath, logoutPath, openPagePath, }: AuthgearProviderProps): react_jsx_runtime.JSX.Element;
|
|
26
28
|
|
|
27
29
|
interface SignInButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
28
30
|
signInOptions?: SignInOptions;
|
|
@@ -32,6 +34,15 @@ declare function SignInButton({ signInOptions, children, ...props }: SignInButto
|
|
|
32
34
|
type SignOutButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
|
33
35
|
declare function SignOutButton({ children, ...props }: SignOutButtonProps): react_jsx_runtime.JSX.Element;
|
|
34
36
|
|
|
37
|
+
type UserSettingsButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;
|
|
38
|
+
/**
|
|
39
|
+
* A button that opens Authgear's account settings page in a new tab
|
|
40
|
+
* for the currently authenticated user. Requires `AuthgearProvider` as an ancestor.
|
|
41
|
+
*
|
|
42
|
+
* Uses `GET /api/auth/open?page=/settings` under the hood — no Server Action needed.
|
|
43
|
+
*/
|
|
44
|
+
declare function UserSettingsButton({ children, ...props }: UserSettingsButtonProps): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
35
46
|
interface UseAuthgearReturn {
|
|
36
47
|
/** Current session state */
|
|
37
48
|
state: SessionState;
|
|
@@ -45,10 +56,12 @@ interface UseAuthgearReturn {
|
|
|
45
56
|
signIn: (options?: SignInOptions) => void;
|
|
46
57
|
/** Navigate to the sign-out endpoint */
|
|
47
58
|
signOut: () => void;
|
|
59
|
+
/** Open an Authgear page (e.g. Page.Settings) in a new tab */
|
|
60
|
+
openPage: (path: string) => void;
|
|
48
61
|
}
|
|
49
62
|
declare function useAuthgear(): UseAuthgearReturn;
|
|
50
63
|
|
|
51
64
|
/** Returns the current user info, or null if not authenticated. */
|
|
52
65
|
declare function useUser(): UserInfo | null;
|
|
53
66
|
|
|
54
|
-
export { AuthgearProvider, type AuthgearProviderProps, SessionState, SignInButton, type SignInButtonProps, type SignInOptions, SignOutButton, type SignOutButtonProps, type UseAuthgearReturn, UserInfo, useAuthgear, useUser };
|
|
67
|
+
export { AuthgearProvider, type AuthgearProviderProps, SessionState, SignInButton, type SignInButtonProps, type SignInOptions, SignOutButton, type SignOutButtonProps, type UseAuthgearReturn, UserInfo, UserSettingsButton, type UserSettingsButtonProps, useAuthgear, useUser };
|
package/dist/client.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
|
+
Page,
|
|
3
4
|
PromptOption,
|
|
4
5
|
SessionState
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-AJJAXXPI.js";
|
|
6
7
|
|
|
7
8
|
// src/components/AuthgearProvider.tsx
|
|
8
9
|
import {
|
|
@@ -18,7 +19,8 @@ function AuthgearProvider({
|
|
|
18
19
|
children,
|
|
19
20
|
userInfoPath = "/api/auth/userinfo",
|
|
20
21
|
loginPath = "/api/auth/login",
|
|
21
|
-
logoutPath = "/api/auth/logout"
|
|
22
|
+
logoutPath = "/api/auth/logout",
|
|
23
|
+
openPagePath = "/api/auth/open"
|
|
22
24
|
}) {
|
|
23
25
|
const [state, setState] = useState("UNKNOWN" /* Unknown */);
|
|
24
26
|
const [user, setUser] = useState(null);
|
|
@@ -70,7 +72,15 @@ function AuthgearProvider({
|
|
|
70
72
|
const signOut = useCallback(() => {
|
|
71
73
|
window.location.href = logoutPath;
|
|
72
74
|
}, [logoutPath]);
|
|
73
|
-
|
|
75
|
+
const openPage = useCallback(
|
|
76
|
+
(path) => {
|
|
77
|
+
const url = new URL(openPagePath, window.location.origin);
|
|
78
|
+
url.searchParams.set("page", path);
|
|
79
|
+
window.open(url.toString(), "_blank", "noopener,noreferrer");
|
|
80
|
+
},
|
|
81
|
+
[openPagePath]
|
|
82
|
+
);
|
|
83
|
+
return /* @__PURE__ */ jsx(AuthgearContext.Provider, { value: { state, user, isLoaded, signIn, signOut, openPage }, children });
|
|
74
84
|
}
|
|
75
85
|
function useAuthgearContext() {
|
|
76
86
|
const ctx = useContext(AuthgearContext);
|
|
@@ -84,26 +94,46 @@ function useAuthgearContext() {
|
|
|
84
94
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
85
95
|
function SignInButton({ signInOptions, children = "Sign In", ...props }) {
|
|
86
96
|
const { signIn } = useAuthgearContext();
|
|
87
|
-
return /* @__PURE__ */ jsx2("button", { ...props, onClick: () =>
|
|
97
|
+
return /* @__PURE__ */ jsx2("button", { ...props, onClick: (e) => {
|
|
98
|
+
props.onClick?.(e);
|
|
99
|
+
signIn(signInOptions);
|
|
100
|
+
}, children });
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
// src/components/SignOutButton.tsx
|
|
91
104
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
92
105
|
function SignOutButton({ children = "Sign Out", ...props }) {
|
|
93
106
|
const { signOut } = useAuthgearContext();
|
|
94
|
-
return /* @__PURE__ */ jsx3("button", { ...props, onClick:
|
|
107
|
+
return /* @__PURE__ */ jsx3("button", { ...props, onClick: (e) => {
|
|
108
|
+
props.onClick?.(e);
|
|
109
|
+
signOut();
|
|
110
|
+
}, children });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/components/UserSettingsButton.tsx
|
|
114
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
115
|
+
function UserSettingsButton({
|
|
116
|
+
children = "Account Settings",
|
|
117
|
+
...props
|
|
118
|
+
}) {
|
|
119
|
+
const { openPage } = useAuthgearContext();
|
|
120
|
+
return /* @__PURE__ */ jsx4("button", { ...props, onClick: (e) => {
|
|
121
|
+
props.onClick?.(e);
|
|
122
|
+
openPage("/settings" /* Settings */);
|
|
123
|
+
}, children });
|
|
95
124
|
}
|
|
96
125
|
|
|
97
126
|
// src/hooks/useAuthgear.ts
|
|
98
127
|
function useAuthgear() {
|
|
99
|
-
const { state, user, isLoaded, signIn, signOut } = useAuthgearContext();
|
|
128
|
+
const { state, user, isLoaded, signIn, signOut, openPage } = useAuthgearContext();
|
|
100
129
|
return {
|
|
101
130
|
state,
|
|
102
131
|
user,
|
|
103
132
|
isLoaded,
|
|
104
133
|
isAuthenticated: state === "AUTHENTICATED" /* Authenticated */,
|
|
105
134
|
signIn,
|
|
106
|
-
signOut
|
|
135
|
+
signOut,
|
|
136
|
+
openPage
|
|
107
137
|
};
|
|
108
138
|
}
|
|
109
139
|
|
|
@@ -114,10 +144,12 @@ function useUser() {
|
|
|
114
144
|
}
|
|
115
145
|
export {
|
|
116
146
|
AuthgearProvider,
|
|
147
|
+
Page,
|
|
117
148
|
PromptOption,
|
|
118
149
|
SessionState,
|
|
119
150
|
SignInButton,
|
|
120
151
|
SignOutButton,
|
|
152
|
+
UserSettingsButton,
|
|
121
153
|
useAuthgear,
|
|
122
154
|
useUser
|
|
123
155
|
};
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/AuthgearProvider.tsx","../src/components/SignInButton.tsx","../src/components/SignOutButton.tsx","../src/hooks/useAuthgear.ts","../src/hooks/useUser.ts"],"sourcesContent":["\"use client\";\n\nimport React, {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport { SessionState, type UserInfo } from \"../types.js\";\n\nexport interface AuthgearContextValue {\n state: SessionState;\n user: UserInfo | null;\n isLoaded: boolean;\n signIn: (options?: SignInOptions) => void;\n signOut: () => void;\n}\n\nexport interface SignInOptions {\n returnTo?: string;\n loginPath?: string;\n /**\n * OIDC `prompt` parameter for this sign-in call.\n * Overrides the global `isSSOEnabled` setting for this navigation.\n * Use `PromptOption.Login` or `PromptOption.None` for type-safe values.\n */\n prompt?: string;\n}\n\nconst AuthgearContext = createContext<AuthgearContextValue | null>(null);\n\nexport interface AuthgearProviderProps {\n children: ReactNode;\n /** Path to the userinfo API route. Defaults to \"/api/auth/userinfo\". */\n userInfoPath?: string;\n /** Path to the login route. Defaults to \"/api/auth/login\". */\n loginPath?: string;\n /** Path to the logout route. Defaults to \"/api/auth/logout\". */\n logoutPath?: string;\n}\n\nexport function AuthgearProvider({\n children,\n userInfoPath = \"/api/auth/userinfo\",\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n}: AuthgearProviderProps) {\n const [state, setState] = useState<SessionState>(SessionState.Unknown);\n const [user, setUser] = useState<UserInfo | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n\n async function fetchSession() {\n try {\n const res = await fetch(userInfoPath);\n if (cancelled) return;\n\n if (res.ok) {\n const userInfo = (await res.json()) as UserInfo;\n setState(SessionState.Authenticated);\n setUser(userInfo);\n } else {\n setState(SessionState.NoSession);\n setUser(null);\n }\n } catch {\n if (!cancelled) {\n setState(SessionState.NoSession);\n setUser(null);\n }\n } finally {\n if (!cancelled) {\n setIsLoaded(true);\n }\n }\n }\n\n fetchSession();\n return () => { cancelled = true; };\n }, [userInfoPath]);\n\n const signIn = useCallback(\n (options?: SignInOptions) => {\n const path = options?.loginPath ?? loginPath;\n const url = new URL(path, window.location.origin);\n if (options?.returnTo) {\n url.searchParams.set(\"returnTo\", options.returnTo);\n }\n if (options?.prompt != null) {\n url.searchParams.set(\"prompt\", options.prompt);\n }\n window.location.href = url.toString();\n },\n [loginPath],\n );\n\n const signOut = useCallback(() => {\n window.location.href = logoutPath;\n }, [logoutPath]);\n\n return (\n <AuthgearContext.Provider value={{ state, user, isLoaded, signIn, signOut }}>\n {children}\n </AuthgearContext.Provider>\n );\n}\n\nexport function useAuthgearContext(): AuthgearContextValue {\n const ctx = useContext(AuthgearContext);\n if (!ctx) {\n throw new Error(\"useAuthgearContext must be used within <AuthgearProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport React, { type ButtonHTMLAttributes } from \"react\";\nimport { useAuthgearContext, type SignInOptions } from \"./AuthgearProvider.js\";\n\nexport interface SignInButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n signInOptions?: SignInOptions;\n}\n\nexport function SignInButton({ signInOptions, children = \"Sign In\", ...props }: SignInButtonProps) {\n const { signIn } = useAuthgearContext();\n return (\n <button {...props} onClick={() => signIn(signInOptions)}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport React, { type ButtonHTMLAttributes } from \"react\";\nimport { useAuthgearContext } from \"./AuthgearProvider.js\";\n\nexport type SignOutButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;\n\nexport function SignOutButton({ children = \"Sign Out\", ...props }: SignOutButtonProps) {\n const { signOut } = useAuthgearContext();\n return (\n <button {...props} onClick={signOut}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport { useAuthgearContext, type SignInOptions } from \"../components/AuthgearProvider.js\";\nimport { SessionState, type UserInfo } from \"../types.js\";\n\nexport interface UseAuthgearReturn {\n /** Current session state */\n state: SessionState;\n /** Current user info, null if not authenticated */\n user: UserInfo | null;\n /** Whether the initial session check has completed */\n isLoaded: boolean;\n /** Whether the user is currently authenticated */\n isAuthenticated: boolean;\n /** Navigate to the sign-in page */\n signIn: (options?: SignInOptions) => void;\n /** Navigate to the sign-out endpoint */\n signOut: () => void;\n}\n\nexport function useAuthgear(): UseAuthgearReturn {\n const { state, user, isLoaded, signIn, signOut } = useAuthgearContext();\n\n return {\n state,\n user,\n isLoaded,\n isAuthenticated: state === SessionState.Authenticated,\n signIn,\n signOut,\n };\n}\n","\"use client\";\n\nimport { useAuthgearContext } from \"../components/AuthgearProvider.js\";\nimport type { UserInfo } from \"../types.js\";\n\n/** Returns the current user info, or null if not authenticated. */\nexport function useUser(): UserInfo | null {\n const { user } = useAuthgearContext();\n return user;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/components/AuthgearProvider.tsx","../src/components/SignInButton.tsx","../src/components/SignOutButton.tsx","../src/components/UserSettingsButton.tsx","../src/hooks/useAuthgear.ts","../src/hooks/useUser.ts"],"sourcesContent":["\"use client\";\n\nimport React, {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport { SessionState, type UserInfo } from \"../types.js\";\n\nexport interface AuthgearContextValue {\n state: SessionState;\n user: UserInfo | null;\n isLoaded: boolean;\n signIn: (options?: SignInOptions) => void;\n signOut: () => void;\n /** Open an Authgear page (e.g. Page.Settings) in a new tab for the current user */\n openPage: (path: string) => void;\n}\n\nexport interface SignInOptions {\n returnTo?: string;\n loginPath?: string;\n /**\n * OIDC `prompt` parameter for this sign-in call.\n * Overrides the global `isSSOEnabled` setting for this navigation.\n * Use `PromptOption.Login` or `PromptOption.None` for type-safe values.\n */\n prompt?: string;\n}\n\nconst AuthgearContext = createContext<AuthgearContextValue | null>(null);\n\nexport interface AuthgearProviderProps {\n children: ReactNode;\n /** Path to the userinfo API route. Defaults to \"/api/auth/userinfo\". */\n userInfoPath?: string;\n /** Path to the login route. Defaults to \"/api/auth/login\". */\n loginPath?: string;\n /** Path to the logout route. Defaults to \"/api/auth/logout\". */\n logoutPath?: string;\n /** Path to the open-page route handler. Defaults to \"/api/auth/open\". */\n openPagePath?: string;\n}\n\nexport function AuthgearProvider({\n children,\n userInfoPath = \"/api/auth/userinfo\",\n loginPath = \"/api/auth/login\",\n logoutPath = \"/api/auth/logout\",\n openPagePath = \"/api/auth/open\",\n}: AuthgearProviderProps) {\n const [state, setState] = useState<SessionState>(SessionState.Unknown);\n const [user, setUser] = useState<UserInfo | null>(null);\n const [isLoaded, setIsLoaded] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n\n async function fetchSession() {\n try {\n const res = await fetch(userInfoPath);\n if (cancelled) return;\n\n if (res.ok) {\n const userInfo = (await res.json()) as UserInfo;\n setState(SessionState.Authenticated);\n setUser(userInfo);\n } else {\n setState(SessionState.NoSession);\n setUser(null);\n }\n } catch {\n if (!cancelled) {\n setState(SessionState.NoSession);\n setUser(null);\n }\n } finally {\n if (!cancelled) {\n setIsLoaded(true);\n }\n }\n }\n\n fetchSession();\n return () => { cancelled = true; };\n }, [userInfoPath]);\n\n const signIn = useCallback(\n (options?: SignInOptions) => {\n const path = options?.loginPath ?? loginPath;\n const url = new URL(path, window.location.origin);\n if (options?.returnTo) {\n url.searchParams.set(\"returnTo\", options.returnTo);\n }\n if (options?.prompt != null) {\n url.searchParams.set(\"prompt\", options.prompt);\n }\n window.location.href = url.toString();\n },\n [loginPath],\n );\n\n const signOut = useCallback(() => {\n window.location.href = logoutPath;\n }, [logoutPath]);\n\n const openPage = useCallback(\n (path: string) => {\n const url = new URL(openPagePath, window.location.origin);\n url.searchParams.set(\"page\", path);\n window.open(url.toString(), \"_blank\", \"noopener,noreferrer\");\n },\n [openPagePath],\n );\n\n return (\n <AuthgearContext.Provider value={{ state, user, isLoaded, signIn, signOut, openPage }}>\n {children}\n </AuthgearContext.Provider>\n );\n}\n\nexport function useAuthgearContext(): AuthgearContextValue {\n const ctx = useContext(AuthgearContext);\n if (!ctx) {\n throw new Error(\"useAuthgearContext must be used within <AuthgearProvider>\");\n }\n return ctx;\n}\n","\"use client\";\n\nimport React, { type ButtonHTMLAttributes } from \"react\";\nimport { useAuthgearContext, type SignInOptions } from \"./AuthgearProvider.js\";\n\nexport interface SignInButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n signInOptions?: SignInOptions;\n}\n\nexport function SignInButton({ signInOptions, children = \"Sign In\", ...props }: SignInButtonProps) {\n const { signIn } = useAuthgearContext();\n return (\n <button {...props} onClick={(e) => { props.onClick?.(e); signIn(signInOptions); }}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport React, { type ButtonHTMLAttributes } from \"react\";\nimport { useAuthgearContext } from \"./AuthgearProvider.js\";\n\nexport type SignOutButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;\n\nexport function SignOutButton({ children = \"Sign Out\", ...props }: SignOutButtonProps) {\n const { signOut } = useAuthgearContext();\n return (\n <button {...props} onClick={(e) => { props.onClick?.(e); signOut(); }}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport React, { type ButtonHTMLAttributes } from \"react\";\nimport { useAuthgearContext } from \"./AuthgearProvider.js\";\nimport { Page } from \"../types.js\";\n\nexport type UserSettingsButtonProps = ButtonHTMLAttributes<HTMLButtonElement>;\n\n/**\n * A button that opens Authgear's account settings page in a new tab\n * for the currently authenticated user. Requires `AuthgearProvider` as an ancestor.\n *\n * Uses `GET /api/auth/open?page=/settings` under the hood — no Server Action needed.\n */\nexport function UserSettingsButton({\n children = \"Account Settings\",\n ...props\n}: UserSettingsButtonProps) {\n const { openPage } = useAuthgearContext();\n return (\n <button {...props} onClick={(e) => { props.onClick?.(e); openPage(Page.Settings); }}>\n {children}\n </button>\n );\n}\n","\"use client\";\n\nimport { useAuthgearContext, type SignInOptions } from \"../components/AuthgearProvider.js\";\nimport { SessionState, type UserInfo } from \"../types.js\";\n\nexport interface UseAuthgearReturn {\n /** Current session state */\n state: SessionState;\n /** Current user info, null if not authenticated */\n user: UserInfo | null;\n /** Whether the initial session check has completed */\n isLoaded: boolean;\n /** Whether the user is currently authenticated */\n isAuthenticated: boolean;\n /** Navigate to the sign-in page */\n signIn: (options?: SignInOptions) => void;\n /** Navigate to the sign-out endpoint */\n signOut: () => void;\n /** Open an Authgear page (e.g. Page.Settings) in a new tab */\n openPage: (path: string) => void;\n}\n\nexport function useAuthgear(): UseAuthgearReturn {\n const { state, user, isLoaded, signIn, signOut, openPage } = useAuthgearContext();\n\n return {\n state,\n user,\n isLoaded,\n isAuthenticated: state === SessionState.Authenticated,\n signIn,\n signOut,\n openPage,\n };\n}\n","\"use client\";\n\nimport { useAuthgearContext } from \"../components/AuthgearProvider.js\";\nimport type { UserInfo } from \"../types.js\";\n\n/** Returns the current user info, or null if not authenticated. */\nexport function useUser(): UserInfo | null {\n const { user } = useAuthgearContext();\n return user;\n}\n"],"mappings":"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","names":["jsx","jsx","jsx"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { A as AuthgearConfig } from './types-
|
|
3
|
-
export { D as DEFAULT_SCOPES, J as JWTPayload, O as OIDCConfiguration, P as Page, a as PromptOption, S as Session, b as SessionData, c as SessionState, T as TokenResponse, U as UserInfo } from './types-
|
|
2
|
+
import { A as AuthgearConfig } from './types-D6m4Hact.js';
|
|
3
|
+
export { D as DEFAULT_SCOPES, J as JWTPayload, O as OIDCConfiguration, P as Page, a as PromptOption, S as Session, b as SessionData, c as SessionState, T as TokenResponse, U as UserInfo } from './types-D6m4Hact.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates Next.js route handlers for all Authgear auth endpoints.
|
|
@@ -17,6 +17,7 @@ export { D as DEFAULT_SCOPES, J as JWTPayload, O as OIDCConfiguration, P as Page
|
|
|
17
17
|
* - GET /api/auth/logout — Logout and revoke tokens
|
|
18
18
|
* - POST /api/auth/refresh — Refresh access token
|
|
19
19
|
* - GET /api/auth/userinfo — Get current user info
|
|
20
|
+
* - GET /api/auth/open — Open an Authgear page (e.g. /settings) for the current user
|
|
20
21
|
*/
|
|
21
22
|
declare function createAuthgearHandlers(config: AuthgearConfig): {
|
|
22
23
|
GET: (request: NextRequest, { params }: {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildAuthorizeURL,
|
|
3
|
+
buildOpenURL,
|
|
3
4
|
generateCodeVerifier,
|
|
4
5
|
generateState,
|
|
5
6
|
parseUserInfo
|
|
@@ -12,20 +13,21 @@ import {
|
|
|
12
13
|
decryptSession,
|
|
13
14
|
exchangeCode,
|
|
14
15
|
fetchOIDCConfiguration,
|
|
16
|
+
getAppSessionToken,
|
|
15
17
|
isTokenExpired,
|
|
16
18
|
refreshAccessToken,
|
|
17
19
|
resolveConfig,
|
|
18
20
|
revokeToken
|
|
19
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-LPGVCNZ6.js";
|
|
20
22
|
import {
|
|
21
23
|
DEFAULT_SCOPES,
|
|
22
24
|
Page,
|
|
23
25
|
PromptOption,
|
|
24
26
|
SessionState
|
|
25
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-AJJAXXPI.js";
|
|
26
28
|
|
|
27
29
|
// src/handlers/index.ts
|
|
28
|
-
import { NextResponse as
|
|
30
|
+
import { NextResponse as NextResponse7 } from "next/server";
|
|
29
31
|
|
|
30
32
|
// src/handlers/login.ts
|
|
31
33
|
import { NextResponse } from "next/server";
|
|
@@ -232,6 +234,46 @@ async function handleUserInfo(request, config) {
|
|
|
232
234
|
return response;
|
|
233
235
|
}
|
|
234
236
|
|
|
237
|
+
// src/handlers/open.ts
|
|
238
|
+
import { NextResponse as NextResponse6 } from "next/server";
|
|
239
|
+
var ALLOWED_PAGES = new Set(Object.values(Page));
|
|
240
|
+
async function handleOpen(request, config) {
|
|
241
|
+
const resolved = resolveConfig(config);
|
|
242
|
+
const pageParam = request.nextUrl.searchParams.get("page");
|
|
243
|
+
if (!pageParam || !ALLOWED_PAGES.has(pageParam)) {
|
|
244
|
+
return NextResponse6.json({ error: "invalid_page" }, { status: 400 });
|
|
245
|
+
}
|
|
246
|
+
const sessionCookieValue = request.cookies.get(resolved.cookieName)?.value;
|
|
247
|
+
if (!sessionCookieValue) {
|
|
248
|
+
return NextResponse6.json({ error: "not_authenticated" }, { status: 401 });
|
|
249
|
+
}
|
|
250
|
+
const sessionData = decryptSession(sessionCookieValue, resolved.sessionSecret);
|
|
251
|
+
if (!sessionData) {
|
|
252
|
+
return NextResponse6.json({ error: "not_authenticated" }, { status: 401 });
|
|
253
|
+
}
|
|
254
|
+
if (!sessionData.refreshToken) {
|
|
255
|
+
return NextResponse6.json({ error: "no_refresh_token" }, { status: 401 });
|
|
256
|
+
}
|
|
257
|
+
const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);
|
|
258
|
+
let app_session_token;
|
|
259
|
+
try {
|
|
260
|
+
const tokenResponse = await getAppSessionToken(
|
|
261
|
+
resolved.endpoint,
|
|
262
|
+
sessionData.refreshToken
|
|
263
|
+
);
|
|
264
|
+
app_session_token = tokenResponse.app_session_token;
|
|
265
|
+
} catch {
|
|
266
|
+
return NextResponse6.json({ error: "not_authenticated" }, { status: 401 });
|
|
267
|
+
}
|
|
268
|
+
const url = buildOpenURL(oidcConfig, {
|
|
269
|
+
clientID: resolved.clientID,
|
|
270
|
+
appSessionToken: app_session_token,
|
|
271
|
+
targetPath: pageParam,
|
|
272
|
+
scopes: resolved.scopes
|
|
273
|
+
});
|
|
274
|
+
return NextResponse6.redirect(url, 302);
|
|
275
|
+
}
|
|
276
|
+
|
|
235
277
|
// src/handlers/index.ts
|
|
236
278
|
function createAuthgearHandlers(config) {
|
|
237
279
|
async function GET(request, { params }) {
|
|
@@ -246,8 +288,10 @@ function createAuthgearHandlers(config) {
|
|
|
246
288
|
return handleLogout(request, config);
|
|
247
289
|
case "userinfo":
|
|
248
290
|
return handleUserInfo(request, config);
|
|
291
|
+
case "open":
|
|
292
|
+
return handleOpen(request, config);
|
|
249
293
|
default:
|
|
250
|
-
return
|
|
294
|
+
return NextResponse7.json({ error: "not_found" }, { status: 404 });
|
|
251
295
|
}
|
|
252
296
|
}
|
|
253
297
|
async function POST(request, { params }) {
|
|
@@ -257,7 +301,7 @@ function createAuthgearHandlers(config) {
|
|
|
257
301
|
case "refresh":
|
|
258
302
|
return handleRefresh(request, config);
|
|
259
303
|
default:
|
|
260
|
-
return
|
|
304
|
+
return NextResponse7.json({ error: "not_found" }, { status: 404 });
|
|
261
305
|
}
|
|
262
306
|
}
|
|
263
307
|
return { GET, POST };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handlers/index.ts","../src/handlers/login.ts","../src/handlers/callback.ts","../src/handlers/logout.ts","../src/handlers/refresh.ts","../src/handlers/userinfo.ts"],"sourcesContent":["import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { handleLogin } from \"./login.js\";\nimport { handleCallback } from \"./callback.js\";\nimport { handleLogout } from \"./logout.js\";\nimport { handleRefresh } from \"./refresh.js\";\nimport { handleUserInfo } from \"./userinfo.js\";\n\n/**\n * Creates Next.js route handlers for all Authgear auth endpoints.\n *\n * Usage in `app/api/auth/[...authgear]/route.ts`:\n * ```ts\n * import { createAuthgearHandlers } from \"@authgear/nextjs\";\n * export const { GET, POST } = createAuthgearHandlers(config);\n * ```\n *\n * Routes handled:\n * - GET /api/auth/login — Start OAuth flow\n * - GET /api/auth/callback — Handle OAuth callback\n * - GET /api/auth/logout — Logout and revoke tokens\n * - POST /api/auth/refresh — Refresh access token\n * - GET /api/auth/userinfo — Get current user info\n */\nexport function createAuthgearHandlers(config: AuthgearConfig) {\n async function GET(\n request: NextRequest,\n { params }: { params: Promise<{ authgear: string[] }> },\n ): Promise<NextResponse> {\n const { authgear } = await params;\n const action = authgear?.[0];\n\n switch (action) {\n case \"login\":\n return handleLogin(request, config);\n case \"callback\":\n return handleCallback(request, config);\n case \"logout\":\n return handleLogout(request, config);\n case \"userinfo\":\n return handleUserInfo(request, config);\n default:\n return NextResponse.json({ error: \"not_found\" }, { status: 404 });\n }\n }\n\n async function POST(\n request: NextRequest,\n { params }: { params: Promise<{ authgear: string[] }> },\n ): Promise<NextResponse> {\n const { authgear } = await params;\n const action = authgear?.[0];\n\n switch (action) {\n case \"refresh\":\n return handleRefresh(request, config);\n default:\n return NextResponse.json({ error: \"not_found\" }, { status: 404 });\n }\n }\n\n return { GET, POST };\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { PromptOption } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { generateCodeVerifier } from \"../oauth/pkce.js\";\nimport { buildAuthorizeURL, generateState } from \"../oauth/authorize.js\";\nimport { buildPKCECookie } from \"../session/cookie.js\";\n\nexport async function handleLogin(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n\n const returnTo = request.nextUrl.searchParams.get(\"returnTo\") ?? \"/\";\n const codeVerifier = generateCodeVerifier();\n const state = generateState();\n\n // Per-call ?prompt= query param takes precedence over the global isSSOEnabled default\n const ALLOWED_PROMPTS = new Set<string>(Object.values(PromptOption));\n const rawPrompt = request.nextUrl.searchParams.get(\"prompt\");\n const perCallPrompt = rawPrompt !== null && ALLOWED_PROMPTS.has(rawPrompt) ? rawPrompt : undefined;\n const prompt = perCallPrompt ?? (resolved.isSSOEnabled ? undefined : \"login\");\n\n const authorizeURL = buildAuthorizeURL(oidcConfig, {\n clientID: resolved.clientID,\n redirectURI: resolved.redirectURI,\n scopes: resolved.scopes,\n codeVerifier,\n state,\n prompt,\n });\n\n const pkceCookie = buildPKCECookie({ codeVerifier, state, returnTo }, resolved.sessionSecret);\n\n const response = NextResponse.redirect(authorizeURL);\n response.cookies.set(pkceCookie.name, pkceCookie.value, {\n httpOnly: pkceCookie.httpOnly,\n secure: pkceCookie.secure,\n sameSite: pkceCookie.sameSite,\n path: pkceCookie.path,\n maxAge: pkceCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { exchangeCode } from \"../oauth/token.js\";\nimport { decryptPKCECookie, buildSessionCookie } from \"../session/cookie.js\";\n\nexport async function handleCallback(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n const error = request.nextUrl.searchParams.get(\"error\");\n const errorDescription = request.nextUrl.searchParams.get(\"error_description\");\n\n if (error) {\n return NextResponse.json(\n { error, error_description: errorDescription },\n { status: 400 },\n );\n }\n\n if (!code || !state) {\n return NextResponse.json(\n { error: \"missing_params\", error_description: \"Missing code or state parameter\" },\n { status: 400 },\n );\n }\n\n // Validate PKCE state\n const pkceCookieValue = request.cookies.get(\"authgear.pkce\")?.value;\n if (!pkceCookieValue) {\n return NextResponse.json(\n { error: \"invalid_state\", error_description: \"Missing PKCE cookie\" },\n { status: 400 },\n );\n }\n\n const pkceData = decryptPKCECookie(pkceCookieValue, resolved.sessionSecret);\n if (!pkceData || pkceData.state !== state) {\n return NextResponse.json(\n { error: \"invalid_state\", error_description: \"State mismatch\" },\n { status: 400 },\n );\n }\n\n // Exchange code for tokens\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n const tokenResponse = await exchangeCode(oidcConfig, {\n code,\n codeVerifier: pkceData.codeVerifier,\n clientID: resolved.clientID,\n redirectURI: resolved.redirectURI,\n });\n\n // Build session cookie\n const sessionCookie = buildSessionCookie(\n resolved.cookieName,\n {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token ?? null,\n idToken: tokenResponse.id_token ?? null,\n expiresAt: Math.floor(Date.now() / 1000) + tokenResponse.expires_in,\n },\n resolved.sessionSecret,\n );\n\n const returnTo = pkceData.returnTo || \"/\";\n const redirectURL = new URL(returnTo, request.nextUrl.origin);\n const response = NextResponse.redirect(redirectURL);\n\n // Set session cookie\n response.cookies.set(sessionCookie.name, sessionCookie.value, {\n httpOnly: sessionCookie.httpOnly,\n secure: sessionCookie.secure,\n sameSite: sessionCookie.sameSite,\n path: sessionCookie.path,\n maxAge: sessionCookie.maxAge,\n });\n\n // Clear PKCE cookie\n response.cookies.set(\"authgear.pkce\", \"\", { maxAge: 0, path: \"/\" });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { revokeToken } from \"../oauth/token.js\";\nimport { decryptSession, buildClearCookie } from \"../session/cookie.js\";\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n // Revoke refresh token if present\n const sessionCookie = request.cookies.get(resolved.cookieName)?.value;\n if (sessionCookie) {\n const session = decryptSession(sessionCookie, resolved.sessionSecret);\n if (session?.refreshToken) {\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n try {\n await revokeToken(oidcConfig, session.refreshToken);\n } catch {\n // Best-effort revocation\n }\n }\n }\n\n const clearCookie = buildClearCookie(resolved.cookieName);\n const redirectURL = new URL(resolved.postLogoutRedirectURI, request.nextUrl.origin);\n const response = NextResponse.redirect(redirectURL);\n\n response.cookies.set(clearCookie.name, clearCookie.value, {\n httpOnly: clearCookie.httpOnly,\n secure: clearCookie.secure,\n sameSite: clearCookie.sameSite,\n path: clearCookie.path,\n maxAge: clearCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { refreshAccessToken } from \"../oauth/token.js\";\nimport { decryptSession, buildSessionCookie } from \"../session/cookie.js\";\n\nexport async function handleRefresh(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const sessionCookieValue = request.cookies.get(resolved.cookieName)?.value;\n if (!sessionCookieValue) {\n return NextResponse.json({ error: \"no_session\" }, { status: 401 });\n }\n\n const session = decryptSession(sessionCookieValue, resolved.sessionSecret);\n if (!session?.refreshToken) {\n return NextResponse.json({ error: \"no_refresh_token\" }, { status: 401 });\n }\n\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n const tokenResponse = await refreshAccessToken(oidcConfig, {\n refreshToken: session.refreshToken,\n clientID: resolved.clientID,\n });\n\n const newSession = {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token ?? session.refreshToken,\n idToken: tokenResponse.id_token ?? session.idToken,\n expiresAt: Math.floor(Date.now() / 1000) + tokenResponse.expires_in,\n };\n\n const sessionCookie = buildSessionCookie(resolved.cookieName, newSession, resolved.sessionSecret);\n const response = NextResponse.json({ ok: true });\n\n response.cookies.set(sessionCookie.name, sessionCookie.value, {\n httpOnly: sessionCookie.httpOnly,\n secure: sessionCookie.secure,\n sameSite: sessionCookie.sameSite,\n path: sessionCookie.path,\n maxAge: sessionCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig, UserInfo } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { decryptSession } from \"../session/cookie.js\";\nimport { isTokenExpired } from \"../session/state.js\";\nimport { refreshAccessToken } from \"../oauth/token.js\";\nimport { buildSessionCookie } from \"../session/cookie.js\";\nimport { parseUserInfo } from \"../user.js\";\n\nexport async function handleUserInfo(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const sessionCookieValue = request.cookies.get(resolved.cookieName)?.value;\n if (!sessionCookieValue) {\n return NextResponse.json({ error: \"no_session\" }, { status: 401 });\n }\n\n let session = decryptSession(sessionCookieValue, resolved.sessionSecret);\n if (!session) {\n return NextResponse.json({ error: \"invalid_session\" }, { status: 401 });\n }\n\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n\n // Auto-refresh if access token is expired\n if (isTokenExpired(session.expiresAt) && session.refreshToken) {\n const tokenResponse = await refreshAccessToken(oidcConfig, {\n refreshToken: session.refreshToken,\n clientID: resolved.clientID,\n });\n session = {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token ?? session.refreshToken,\n idToken: tokenResponse.id_token ?? session.idToken,\n expiresAt: Math.floor(Date.now() / 1000) + tokenResponse.expires_in,\n };\n }\n\n // Fetch user info from Authgear\n const userinfoRes = await fetch(oidcConfig.userinfo_endpoint, {\n headers: { Authorization: `Bearer ${session.accessToken}` },\n });\n\n if (!userinfoRes.ok) {\n return NextResponse.json({ error: \"userinfo_failed\" }, { status: userinfoRes.status });\n }\n\n const raw = (await userinfoRes.json()) as Record<string, unknown>;\n const userInfo: UserInfo = parseUserInfo(raw);\n\n const response = NextResponse.json(userInfo);\n\n // Update session cookie if tokens were refreshed\n const newCookie = buildSessionCookie(resolved.cookieName, session, resolved.sessionSecret);\n response.cookies.set(newCookie.name, newCookie.value, {\n httpOnly: newCookie.httpOnly,\n secure: newCookie.secure,\n sameSite: newCookie.sameSite,\n path: newCookie.path,\n maxAge: newCookie.maxAge,\n });\n\n return response;\n}\n"],"mappings":"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","names":["NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse"]}
|
|
1
|
+
{"version":3,"sources":["../src/handlers/index.ts","../src/handlers/login.ts","../src/handlers/callback.ts","../src/handlers/logout.ts","../src/handlers/refresh.ts","../src/handlers/userinfo.ts","../src/handlers/open.ts"],"sourcesContent":["import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { handleLogin } from \"./login.js\";\nimport { handleCallback } from \"./callback.js\";\nimport { handleLogout } from \"./logout.js\";\nimport { handleRefresh } from \"./refresh.js\";\nimport { handleUserInfo } from \"./userinfo.js\";\nimport { handleOpen } from \"./open.js\";\n\n/**\n * Creates Next.js route handlers for all Authgear auth endpoints.\n *\n * Usage in `app/api/auth/[...authgear]/route.ts`:\n * ```ts\n * import { createAuthgearHandlers } from \"@authgear/nextjs\";\n * export const { GET, POST } = createAuthgearHandlers(config);\n * ```\n *\n * Routes handled:\n * - GET /api/auth/login — Start OAuth flow\n * - GET /api/auth/callback — Handle OAuth callback\n * - GET /api/auth/logout — Logout and revoke tokens\n * - POST /api/auth/refresh — Refresh access token\n * - GET /api/auth/userinfo — Get current user info\n * - GET /api/auth/open — Open an Authgear page (e.g. /settings) for the current user\n */\nexport function createAuthgearHandlers(config: AuthgearConfig) {\n async function GET(\n request: NextRequest,\n { params }: { params: Promise<{ authgear: string[] }> },\n ): Promise<NextResponse> {\n const { authgear } = await params;\n const action = authgear?.[0];\n\n switch (action) {\n case \"login\":\n return handleLogin(request, config);\n case \"callback\":\n return handleCallback(request, config);\n case \"logout\":\n return handleLogout(request, config);\n case \"userinfo\":\n return handleUserInfo(request, config);\n case \"open\":\n return handleOpen(request, config);\n default:\n return NextResponse.json({ error: \"not_found\" }, { status: 404 });\n }\n }\n\n async function POST(\n request: NextRequest,\n { params }: { params: Promise<{ authgear: string[] }> },\n ): Promise<NextResponse> {\n const { authgear } = await params;\n const action = authgear?.[0];\n\n switch (action) {\n case \"refresh\":\n return handleRefresh(request, config);\n default:\n return NextResponse.json({ error: \"not_found\" }, { status: 404 });\n }\n }\n\n return { GET, POST };\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { PromptOption } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { generateCodeVerifier } from \"../oauth/pkce.js\";\nimport { buildAuthorizeURL, generateState } from \"../oauth/authorize.js\";\nimport { buildPKCECookie } from \"../session/cookie.js\";\n\nexport async function handleLogin(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n\n const returnTo = request.nextUrl.searchParams.get(\"returnTo\") ?? \"/\";\n const codeVerifier = generateCodeVerifier();\n const state = generateState();\n\n // Per-call ?prompt= query param takes precedence over the global isSSOEnabled default\n const ALLOWED_PROMPTS = new Set<string>(Object.values(PromptOption));\n const rawPrompt = request.nextUrl.searchParams.get(\"prompt\");\n const perCallPrompt = rawPrompt !== null && ALLOWED_PROMPTS.has(rawPrompt) ? rawPrompt : undefined;\n const prompt = perCallPrompt ?? (resolved.isSSOEnabled ? undefined : \"login\");\n\n const authorizeURL = buildAuthorizeURL(oidcConfig, {\n clientID: resolved.clientID,\n redirectURI: resolved.redirectURI,\n scopes: resolved.scopes,\n codeVerifier,\n state,\n prompt,\n });\n\n const pkceCookie = buildPKCECookie({ codeVerifier, state, returnTo }, resolved.sessionSecret);\n\n const response = NextResponse.redirect(authorizeURL);\n response.cookies.set(pkceCookie.name, pkceCookie.value, {\n httpOnly: pkceCookie.httpOnly,\n secure: pkceCookie.secure,\n sameSite: pkceCookie.sameSite,\n path: pkceCookie.path,\n maxAge: pkceCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { exchangeCode } from \"../oauth/token.js\";\nimport { decryptPKCECookie, buildSessionCookie } from \"../session/cookie.js\";\n\nexport async function handleCallback(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const code = request.nextUrl.searchParams.get(\"code\");\n const state = request.nextUrl.searchParams.get(\"state\");\n const error = request.nextUrl.searchParams.get(\"error\");\n const errorDescription = request.nextUrl.searchParams.get(\"error_description\");\n\n if (error) {\n return NextResponse.json(\n { error, error_description: errorDescription },\n { status: 400 },\n );\n }\n\n if (!code || !state) {\n return NextResponse.json(\n { error: \"missing_params\", error_description: \"Missing code or state parameter\" },\n { status: 400 },\n );\n }\n\n // Validate PKCE state\n const pkceCookieValue = request.cookies.get(\"authgear.pkce\")?.value;\n if (!pkceCookieValue) {\n return NextResponse.json(\n { error: \"invalid_state\", error_description: \"Missing PKCE cookie\" },\n { status: 400 },\n );\n }\n\n const pkceData = decryptPKCECookie(pkceCookieValue, resolved.sessionSecret);\n if (!pkceData || pkceData.state !== state) {\n return NextResponse.json(\n { error: \"invalid_state\", error_description: \"State mismatch\" },\n { status: 400 },\n );\n }\n\n // Exchange code for tokens\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n const tokenResponse = await exchangeCode(oidcConfig, {\n code,\n codeVerifier: pkceData.codeVerifier,\n clientID: resolved.clientID,\n redirectURI: resolved.redirectURI,\n });\n\n // Build session cookie\n const sessionCookie = buildSessionCookie(\n resolved.cookieName,\n {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token ?? null,\n idToken: tokenResponse.id_token ?? null,\n expiresAt: Math.floor(Date.now() / 1000) + tokenResponse.expires_in,\n },\n resolved.sessionSecret,\n );\n\n const returnTo = pkceData.returnTo || \"/\";\n const redirectURL = new URL(returnTo, request.nextUrl.origin);\n const response = NextResponse.redirect(redirectURL);\n\n // Set session cookie\n response.cookies.set(sessionCookie.name, sessionCookie.value, {\n httpOnly: sessionCookie.httpOnly,\n secure: sessionCookie.secure,\n sameSite: sessionCookie.sameSite,\n path: sessionCookie.path,\n maxAge: sessionCookie.maxAge,\n });\n\n // Clear PKCE cookie\n response.cookies.set(\"authgear.pkce\", \"\", { maxAge: 0, path: \"/\" });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { revokeToken } from \"../oauth/token.js\";\nimport { decryptSession, buildClearCookie } from \"../session/cookie.js\";\n\nexport async function handleLogout(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n // Revoke refresh token if present\n const sessionCookie = request.cookies.get(resolved.cookieName)?.value;\n if (sessionCookie) {\n const session = decryptSession(sessionCookie, resolved.sessionSecret);\n if (session?.refreshToken) {\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n try {\n await revokeToken(oidcConfig, session.refreshToken);\n } catch {\n // Best-effort revocation\n }\n }\n }\n\n const clearCookie = buildClearCookie(resolved.cookieName);\n const redirectURL = new URL(resolved.postLogoutRedirectURI, request.nextUrl.origin);\n const response = NextResponse.redirect(redirectURL);\n\n response.cookies.set(clearCookie.name, clearCookie.value, {\n httpOnly: clearCookie.httpOnly,\n secure: clearCookie.secure,\n sameSite: clearCookie.sameSite,\n path: clearCookie.path,\n maxAge: clearCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { refreshAccessToken } from \"../oauth/token.js\";\nimport { decryptSession, buildSessionCookie } from \"../session/cookie.js\";\n\nexport async function handleRefresh(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const sessionCookieValue = request.cookies.get(resolved.cookieName)?.value;\n if (!sessionCookieValue) {\n return NextResponse.json({ error: \"no_session\" }, { status: 401 });\n }\n\n const session = decryptSession(sessionCookieValue, resolved.sessionSecret);\n if (!session?.refreshToken) {\n return NextResponse.json({ error: \"no_refresh_token\" }, { status: 401 });\n }\n\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n const tokenResponse = await refreshAccessToken(oidcConfig, {\n refreshToken: session.refreshToken,\n clientID: resolved.clientID,\n });\n\n const newSession = {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token ?? session.refreshToken,\n idToken: tokenResponse.id_token ?? session.idToken,\n expiresAt: Math.floor(Date.now() / 1000) + tokenResponse.expires_in,\n };\n\n const sessionCookie = buildSessionCookie(resolved.cookieName, newSession, resolved.sessionSecret);\n const response = NextResponse.json({ ok: true });\n\n response.cookies.set(sessionCookie.name, sessionCookie.value, {\n httpOnly: sessionCookie.httpOnly,\n secure: sessionCookie.secure,\n sameSite: sessionCookie.sameSite,\n path: sessionCookie.path,\n maxAge: sessionCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig, UserInfo } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { decryptSession } from \"../session/cookie.js\";\nimport { isTokenExpired } from \"../session/state.js\";\nimport { refreshAccessToken } from \"../oauth/token.js\";\nimport { buildSessionCookie } from \"../session/cookie.js\";\nimport { parseUserInfo } from \"../user.js\";\n\nexport async function handleUserInfo(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const sessionCookieValue = request.cookies.get(resolved.cookieName)?.value;\n if (!sessionCookieValue) {\n return NextResponse.json({ error: \"no_session\" }, { status: 401 });\n }\n\n let session = decryptSession(sessionCookieValue, resolved.sessionSecret);\n if (!session) {\n return NextResponse.json({ error: \"invalid_session\" }, { status: 401 });\n }\n\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n\n // Auto-refresh if access token is expired\n if (isTokenExpired(session.expiresAt) && session.refreshToken) {\n const tokenResponse = await refreshAccessToken(oidcConfig, {\n refreshToken: session.refreshToken,\n clientID: resolved.clientID,\n });\n session = {\n accessToken: tokenResponse.access_token,\n refreshToken: tokenResponse.refresh_token ?? session.refreshToken,\n idToken: tokenResponse.id_token ?? session.idToken,\n expiresAt: Math.floor(Date.now() / 1000) + tokenResponse.expires_in,\n };\n }\n\n // Fetch user info from Authgear\n const userinfoRes = await fetch(oidcConfig.userinfo_endpoint, {\n headers: { Authorization: `Bearer ${session.accessToken}` },\n });\n\n if (!userinfoRes.ok) {\n return NextResponse.json({ error: \"userinfo_failed\" }, { status: userinfoRes.status });\n }\n\n const raw = (await userinfoRes.json()) as Record<string, unknown>;\n const userInfo: UserInfo = parseUserInfo(raw);\n\n const response = NextResponse.json(userInfo);\n\n // Update session cookie if tokens were refreshed\n const newCookie = buildSessionCookie(resolved.cookieName, session, resolved.sessionSecret);\n response.cookies.set(newCookie.name, newCookie.value, {\n httpOnly: newCookie.httpOnly,\n secure: newCookie.secure,\n sameSite: newCookie.sameSite,\n path: newCookie.path,\n maxAge: newCookie.maxAge,\n });\n\n return response;\n}\n","import { NextResponse, type NextRequest } from \"next/server\";\nimport type { AuthgearConfig } from \"../types.js\";\nimport { Page } from \"../types.js\";\nimport { resolveConfig } from \"../config.js\";\nimport { fetchOIDCConfiguration } from \"../oauth/discovery.js\";\nimport { getAppSessionToken } from \"../oauth/token.js\";\nimport { buildOpenURL } from \"../oauth/authorize.js\";\nimport { decryptSession } from \"../session/cookie.js\";\n\nconst ALLOWED_PAGES = new Set<string>(Object.values(Page));\n\nexport async function handleOpen(\n request: NextRequest,\n config: AuthgearConfig,\n): Promise<NextResponse> {\n const resolved = resolveConfig(config);\n\n const pageParam = request.nextUrl.searchParams.get(\"page\");\n if (!pageParam || !ALLOWED_PAGES.has(pageParam)) {\n return NextResponse.json({ error: \"invalid_page\" }, { status: 400 });\n }\n\n const sessionCookieValue = request.cookies.get(resolved.cookieName)?.value;\n if (!sessionCookieValue) {\n return NextResponse.json({ error: \"not_authenticated\" }, { status: 401 });\n }\n\n const sessionData = decryptSession(sessionCookieValue, resolved.sessionSecret);\n if (!sessionData) {\n return NextResponse.json({ error: \"not_authenticated\" }, { status: 401 });\n }\n\n if (!sessionData.refreshToken) {\n return NextResponse.json({ error: \"no_refresh_token\" }, { status: 401 });\n }\n\n const oidcConfig = await fetchOIDCConfiguration(resolved.endpoint);\n\n let app_session_token: string;\n try {\n const tokenResponse = await getAppSessionToken(\n resolved.endpoint,\n sessionData.refreshToken,\n );\n app_session_token = tokenResponse.app_session_token;\n } catch {\n return NextResponse.json({ error: \"not_authenticated\" }, { status: 401 });\n }\n\n const url = buildOpenURL(oidcConfig, {\n clientID: resolved.clientID,\n appSessionToken: app_session_token,\n targetPath: pageParam,\n scopes: resolved.scopes,\n });\n\n return NextResponse.redirect(url, 302);\n}\n"],"mappings":"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","names":["NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse","NextResponse"]}
|
package/dist/proxy.d.ts
CHANGED
package/dist/proxy.js
CHANGED
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
isTokenExpired,
|
|
6
6
|
refreshAccessToken,
|
|
7
7
|
resolveConfig
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-LPGVCNZ6.js";
|
|
9
|
+
import "./chunk-AJJAXXPI.js";
|
|
10
10
|
|
|
11
11
|
// src/proxy.ts
|
|
12
12
|
import { NextResponse } from "next/server";
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AuthgearConfig, S as Session, U as UserInfo, P as Page, J as JWTPayload } from './types-
|
|
2
|
-
export { a as PromptOption, c as SessionState } from './types-
|
|
1
|
+
import { A as AuthgearConfig, S as Session, U as UserInfo, P as Page, J as JWTPayload } from './types-D6m4Hact.js';
|
|
2
|
+
export { a as PromptOption, c as SessionState } from './types-D6m4Hact.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Read the current session in a Server Component, Route Handler, or Server Action.
|
package/dist/server.js
CHANGED
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
isTokenExpired,
|
|
12
12
|
refreshAccessToken,
|
|
13
13
|
resolveConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-LPGVCNZ6.js";
|
|
15
15
|
import {
|
|
16
16
|
Page,
|
|
17
17
|
PromptOption,
|
|
18
18
|
SessionState
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-AJJAXXPI.js";
|
|
20
20
|
|
|
21
21
|
// src/server.ts
|
|
22
22
|
import "server-only";
|
|
@@ -24,7 +24,9 @@ interface AuthgearConfig {
|
|
|
24
24
|
isSSOEnabled?: boolean;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Pages that can be opened
|
|
27
|
+
* Pages that can be opened in a new tab with the current user pre-authenticated.
|
|
28
|
+
* Used by `getOpenURL` from `@authgear/nextjs/server` and by `openPage` / `<UserSettingsButton>`
|
|
29
|
+
* from `@authgear/nextjs/client`.
|
|
28
30
|
*/
|
|
29
31
|
declare enum Page {
|
|
30
32
|
Settings = "/settings"
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export interface AuthgearConfig {\n /** Authgear endpoint, e.g. \"https://myapp.authgear.cloud\" */\n endpoint: string;\n /** OAuth client ID */\n clientID: string;\n /** Redirect URI for OAuth callback, e.g. \"http://localhost:3000/api/auth/callback\" */\n redirectURI: string;\n /** Where to redirect after logout */\n postLogoutRedirectURI?: string;\n /** OAuth scopes. Defaults to [\"openid\", \"offline_access\", \"https://authgear.com/scopes/full-userinfo\"] */\n scopes?: string[];\n /** Secret key for encrypting session cookie (min 32 chars) */\n sessionSecret: string;\n /** Session cookie name. Defaults to \"authgear.session\" */\n cookieName?: string;\n /**\n * Whether to enable SSO (Single Sign-On) with other apps on the same Authgear tenant.\n * When `true` (default), Authgear silently reuses its server-side session if the user\n * is already logged in, so users are not prompted for credentials again.\n * Set to `false` to always show the login form (`prompt=login`), which is recommended\n * for single-app deployments where silent sign-in feels unexpected to the user.\n * Defaults to `true`.\n */\n isSSOEnabled?: boolean;\n}\n\n/**\n * Pages that can be opened via `getOpenURL` from `@authgear/nextjs/server`.\n */\nexport enum Page {\n Settings = \"/settings\",\n}\n\n/**\n * OIDC `prompt` parameter values.\n * Pass to `signIn({ prompt })` or `SignInButton signInOptions={{ prompt }}` to control\n * whether Authgear shows the login form for a specific authentication call.\n *\n * @see https://docs.authgear.com/authentication-and-access/single-sign-on/force-authgear-to-show-login-page\n */\nexport enum PromptOption {\n /** Always show the login form, even if the user has an active Authgear session. */\n Login = \"login\",\n /** Never show the login form; return an error if the user is not already authenticated. */\n None = \"none\",\n}\n\nexport const DEFAULT_SCOPES = [\n \"openid\",\n \"offline_access\",\n \"https://authgear.com/scopes/full-userinfo\",\n];\n\nexport enum SessionState {\n Unknown = \"UNKNOWN\",\n NoSession = \"NO_SESSION\",\n Authenticated = \"AUTHENTICATED\",\n}\n\nexport interface SessionData {\n accessToken: string;\n refreshToken: string | null;\n idToken: string | null;\n expiresAt: number;\n}\n\nexport interface Session {\n state: SessionState;\n accessToken: string | null;\n refreshToken: string | null;\n idToken: string | null;\n expiresAt: number | null;\n user: UserInfo | null;\n}\n\nexport interface UserInfo {\n sub: string;\n email?: string;\n emailVerified?: boolean;\n phoneNumber?: string;\n phoneNumberVerified?: boolean;\n preferredUsername?: string;\n givenName?: string;\n familyName?: string;\n name?: string;\n picture?: string;\n roles?: string[];\n isAnonymous?: boolean;\n isVerified?: boolean;\n canReauthenticate?: boolean;\n customAttributes?: Record<string, unknown>;\n raw: Record<string, unknown>;\n}\n\nexport interface JWTPayload {\n sub: string;\n iss: string;\n aud: string | string[];\n exp: number;\n iat: number;\n jti?: string;\n client_id?: string;\n \"https://authgear.com/claims/user/is_anonymous\"?: boolean;\n \"https://authgear.com/claims/user/is_verified\"?: boolean;\n \"https://authgear.com/claims/user/can_reauthenticate\"?: boolean;\n \"https://authgear.com/claims/user/roles\"?: string[];\n [key: string]: unknown;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n id_token?: string;\n}\n\nexport interface AppSessionTokenResponse {\n app_session_token: string;\n expire_at: string;\n}\n\nexport interface OIDCConfiguration {\n authorization_endpoint: string;\n token_endpoint: string;\n userinfo_endpoint: string;\n revocation_endpoint: string;\n end_session_endpoint: string;\n jwks_uri: string;\n issuer: string;\n}\n"],"mappings":";AA6BO,IAAK,OAAL,kBAAKA,UAAL;AACL,EAAAA,MAAA,cAAW;AADD,SAAAA;AAAA,GAAA;AAWL,IAAK,eAAL,kBAAKC,kBAAL;AAEL,EAAAA,cAAA,WAAQ;AAER,EAAAA,cAAA,UAAO;AAJG,SAAAA;AAAA,GAAA;AAOL,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAK,eAAL,kBAAKC,kBAAL;AACL,EAAAA,cAAA,aAAU;AACV,EAAAA,cAAA,eAAY;AACZ,EAAAA,cAAA,mBAAgB;AAHN,SAAAA;AAAA,GAAA;","names":["Page","PromptOption","SessionState"]}
|
|
File without changes
|