Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nextjs: implement SSR functions to retrieve user and access token info #10

Merged
merged 3 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"node": true,
"jest/globals": true
},
"globals": {
"RequestInit": true
},
"ignorePatterns": [
"build/"
],
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
}
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript"
Expand Down
10 changes: 7 additions & 3 deletions nextjs/react/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"name": "@fief/fief/nextjs/react",
"private": true,
"main": "../../build/cjs/nextjs/react.js",
"module": "../../build/esm/nextjs/react.js",
"types": "../../build/esm/nextjs/react.d.ts"
"main": "../../build/cjs/nextjs/react/index.js",
"module": "../../build/esm/nextjs/react/index.js",
"types": "../../build/esm/nextjs/react/index.d.ts",
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
3,607 changes: 1,924 additions & 1,683 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"jest-location-mock": "^2.0.0",
"next": "^13.2.4",
"next": "^14.2.3",
"node-fetch": "^2.7.0",
"node-mocks-http": "^1.11.0",
"ramda": "^0.29.0",
Expand All @@ -74,7 +74,7 @@
},
"dependencies": {
"encoding": "^0.1.13",
"jose": "^4.6.0",
"jose": "^5.4.0",
"path-to-regexp": "^6.2.1"
},
"jest": {}
Expand Down
12 changes: 10 additions & 2 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ const external = [
'crypto',
'jose',
'next',
'next/cache',
'next/headers',
'next/server',
'path-to-regexp',
'react',
'react/jsx-runtime',
];
const globals = {
crypto: 'crypto',
};

export default [
// browser-friendly UMD build
Expand All @@ -23,6 +28,7 @@ export default [
file: 'build/index.umd.js',
format: 'umd',
sourcemap: true,
globals,
},
plugins: [
nodeResolve({
Expand All @@ -43,7 +49,7 @@ export default [
'src/react/index.ts',
'src/express/index.ts',
'src/nextjs/index.ts',
'src/nextjs/react.tsx',
'src/nextjs/react/index.ts',
],
plugins: [
typescript({
Expand All @@ -59,6 +65,7 @@ export default [
sourcemap: true,
preserveModules: true,
preserveModulesRoot: 'src',
globals,
},
],
external,
Expand All @@ -70,7 +77,7 @@ export default [
'src/react/index.ts',
'src/express/index.ts',
'src/nextjs/index.ts',
'src/nextjs/react.tsx',
'src/nextjs/react/index.ts',
],
plugins: [
typescript({
Expand All @@ -87,6 +94,7 @@ export default [
sourcemap: true,
preserveModules: true,
preserveModulesRoot: 'src',
globals,
},
],
external,
Expand Down
45 changes: 44 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,16 @@ export interface FiefParameters {
* @see [ID Token encryption](https://docs.fief.dev/going-further/id-token-encryption/)
*/
encryptionKey?: string;

/**
* Additional fetch init options for `getOpenIDConfiguration` and `getJWKS` requests.
*
* Mostly useful to control fetch cache.
*
* @see [fetch cache property](https://developer.mozilla.org/en-US/docs/Web/API/Request/cache)
* @see [Next.js fetch](https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options)
*/
requestInit?: RequestInit;
}

/**
Expand All @@ -253,6 +263,8 @@ export class Fief {

private fetch: typeof fetch;

private requestInit?: RequestInit;

private openIDConfiguration?: Record<string, any>;

private jwks?: jose.JSONWebKeySet;
Expand All @@ -274,6 +286,7 @@ export class Fief {
}

this.fetch = getFetch();
this.requestInit = parameters.requestInit;

this.crypto = getCrypto();
}
Expand Down Expand Up @@ -348,6 +361,7 @@ export class Fief {
* @param redirectURI - The exact same `redirectURI` you passed to the authorization URL.
* @param codeVerifier - The raw [PKCE](https://docs.fief.dev/going-further/pkce/) code
* used to generate the code challenge during authorization.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns A token response and user information.
*
Expand All @@ -360,6 +374,7 @@ export class Fief {
code: string,
redirectURI: string,
codeVerifier?: string,
requestInit?: RequestInit,
): Promise<[FiefTokenResponse, FiefUserInfo]> {
const openIDConfiguration = await this.getOpenIDConfiguration();
const payload = serializeQueryString({
Expand All @@ -374,9 +389,11 @@ export class Fief {
const response = await this.fetch(
openIDConfiguration.token_endpoint,
{
...requestInit || {},
method: 'POST',
body: payload,
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
'Content-Type': 'application/x-www-form-urlencoded',
},
},
Expand All @@ -402,6 +419,7 @@ export class Fief {
* If not provided, the access token will share the same list of scopes
* as requested the first time.
* Otherwise, it should be a subset of the original list of scopes.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns A token response and user information.
*
Expand All @@ -413,6 +431,7 @@ export class Fief {
public async authRefreshToken(
refreshToken: string,
scope?: string[],
requestInit?: RequestInit,
): Promise<[FiefTokenResponse, FiefUserInfo]> {
const openIDConfiguration = await this.getOpenIDConfiguration();
const payload = serializeQueryString({
Expand All @@ -425,9 +444,11 @@ export class Fief {
const response = await this.fetch(
openIDConfiguration.token_endpoint,
{
...requestInit || {},
method: 'POST',
body: payload,
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
'Content-Type': 'application/x-www-form-urlencoded',
},
},
Expand All @@ -452,6 +473,7 @@ export class Fief {
* @param requiredScopes - Optional list of scopes to check for.
* @param requiredACR - Optional minimum ACR level required. Read more: https://docs.fief.dev/going-further/acr/
* @param requiredPermissions - Optional list of permissions to check for.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns {@link FiefAccessTokenInfo}
* @throws {@link FiefAccessTokenInvalid} if the access token is invalid.
Expand Down Expand Up @@ -548,6 +570,7 @@ export class Fief {
* Return fresh {@link FiefUserInfo} from the Fief API using a valid access token.
*
* @param accessToken - A valid access token.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns Fresh user information.
*
Expand All @@ -556,13 +579,15 @@ export class Fief {
* userinfo = await fief.userinfo('ACCESS_TOKEN');
* ```
*/
public async userinfo(accessToken: string): Promise<FiefUserInfo> {
public async userinfo(accessToken: string, requestInit?: RequestInit): Promise<FiefUserInfo> {
const openIDConfiguration = await this.getOpenIDConfiguration();
const response = await this.fetch(
openIDConfiguration.userinfo_endpoint,
{
...requestInit || {},
method: 'GET',
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
Authorization: `Bearer ${accessToken}`,
},
},
Expand All @@ -577,6 +602,7 @@ export class Fief {
*
* @param accessToken - A valid access token.
* @param data - An object containing the data to update.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns Updated user information.
*
Expand All @@ -590,14 +616,17 @@ export class Fief {
public async updateProfile(
accessToken: string,
data: Record<string, any>,
requestInit?: RequestInit,
): Promise<FiefUserInfo> {
const updateProfileEndpoint = `${this.baseURL}/api/profile`;
const response = await this.fetch(
updateProfileEndpoint,
{
...requestInit || {},
method: 'PATCH',
body: JSON.stringify(data),
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
Expand All @@ -615,6 +644,7 @@ export class Fief {
*
* @param accessToken - A valid access token.
* @param newPassword - The new password.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns Updated user information.
*
Expand All @@ -626,14 +656,17 @@ export class Fief {
public async changePassword(
accessToken: string,
newPassword: string,
requestInit?: RequestInit,
): Promise<FiefUserInfo> {
const updateProfileEndpoint = `${this.baseURL}/api/password`;
const response = await this.fetch(
updateProfileEndpoint,
{
...requestInit || {},
method: 'PATCH',
body: JSON.stringify({ password: newPassword }),
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
Expand All @@ -654,6 +687,7 @@ export class Fief {
*
* @param accessToken - A valid access token.
* @param newPassword - The new email address.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns Updated user information.
*
Expand All @@ -665,14 +699,17 @@ export class Fief {
public async emailChange(
accessToken: string,
email: string,
requestInit?: RequestInit,
): Promise<FiefUserInfo> {
const updateProfileEndpoint = `${this.baseURL}/api/email/change`;
const response = await this.fetch(
updateProfileEndpoint,
{
...requestInit || {},
method: 'PATCH',
body: JSON.stringify({ email }),
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
Expand All @@ -691,6 +728,7 @@ export class Fief {
*
* @param accessToken - A valid access token.
* @param newPassword - The new email address.
* @param requestInit - Additional fetch init options. Mostly useful to control fetch cache.
*
* @returns Updated user information.
*
Expand All @@ -702,14 +740,17 @@ export class Fief {
public async emailVerify(
accessToken: string,
code: string,
requestInit?: RequestInit,
): Promise<FiefUserInfo> {
const updateProfileEndpoint = `${this.baseURL}/api/email/verify`;
const response = await this.fetch(
updateProfileEndpoint,
{
...requestInit || {},
method: 'POST',
body: JSON.stringify({ code }),
headers: {
...requestInit && requestInit.headers ? requestInit.headers : {},
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
Expand Down Expand Up @@ -752,6 +793,7 @@ export class Fief {
const response = await this.fetch(
`${this.baseURL}/.well-known/openid-configuration`,
{
...this.requestInit || {},
method: 'GET',
},
);
Expand All @@ -771,6 +813,7 @@ export class Fief {
const response = await this.fetch(
openIDConfiguration.jwks_uri,
{
...this.requestInit || {},
method: 'GET',
},
);
Expand Down
3 changes: 2 additions & 1 deletion src/crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ export const getCrypto = (): ICryptoHelper => {
throw new CryptoHelperError('Cannot find a crypto implementation for your environment');
};

export { CryptoHelperError, ICryptoHelper };
export { CryptoHelperError };
export type { ICryptoHelper };
4 changes: 3 additions & 1 deletion src/express/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,12 @@ const createMiddleware = (parameters: FiefAuthParameters) => {
};

export {
AuthenticateRequestParameters,
authorizationSchemeGetter,
cookieGetter,
createMiddleware,
};
export type {
AuthenticateRequestParameters,
IUserInfoCache,
TokenGetter,
};
Loading
Loading