Skip to content

Commit

Permalink
added more to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
codercatdev committed Feb 7, 2025
1 parent ff18267 commit d247690
Showing 1 changed file with 167 additions and 0 deletions.
167 changes: 167 additions & 0 deletions packages/core/src/providers/fusionauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,170 @@ export interface FusionAuthProfile extends Record<string, any> {
* we might not pursue a resolution. You can ask for more help in [Discussions](https://authjs.dev/new/github-discussions).
*
* :::
*
*
* It is highly recommended to follow this example call when using the provider in Next.js
* so that you can access both the access_token and id_token on the server.
*
* /// <reference types="next-auth" />
import NextAuth from 'next-auth';
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
{
id: 'fusionauth',
name: 'FusionAuth',
type: 'oidc',
issuer: process.env.AUTH_FUSIONAUTH_ISSUER!,
clientId: process.env.AUTH_FUSIONAUTH_CLIENT_ID!,
clientSecret: process.env.AUTH_FUSIONAUTH_CLIENT_SECRET!,
authorization: {
params: {
scope: 'offline_access email openid profile',
tenantId: process.env.AUTH_FUSIONAUTH_TENANT_ID!,
},
},
userinfo: `${process.env.AUTH_FUSIONAUTH_ISSUER}/oauth2/userinfo`,
// This is due to a known processing issue
// TODO: https://github.com/nextauthjs/next-auth/issues/8745#issuecomment-1907799026
token: {
url: `${process.env.AUTH_FUSIONAUTH_ISSUER}/oauth2/token`,
conform: async (response: Response) => {
if (response.status === 401) return response;
const newHeaders = Array.from(response.headers.entries())
.filter(([key]) => key.toLowerCase() !== 'www-authenticate')
.reduce(
(headers, [key, value]) => (headers.append(key, value), headers),
new Headers()
);
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders,
});
},
},
},
],
session: {
strategy: 'jwt',
},
// Required to get the account object in the session and enable
// the ability to call API's externally that rely on JWT tokens.
callbacks: {
async jwt(params) {
const { token, user, account } = params;
if (account) {
// First-time login, save the `access_token`, its expiry and the `refresh_token`
return {
...token,
...account,
};
} else if (
token.expires_at &&
Date.now() < (token.expires_at as number) * 1000
) {
// Subsequent logins, but the `access_token` is still valid
return token;
} else {
// Subsequent logins, but the `access_token` has expired, try to refresh it
if (!token.refresh_token) throw new TypeError('Missing refresh_token');
try {
const refreshResponse = await fetch(
`${process.env.AUTH_FUSIONAUTH_ISSUER}/oauth2/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: process.env.AUTH_FUSIONAUTH_CLIENT_ID!,
client_secret: process.env.AUTH_FUSIONAUTH_CLIENT_SECRET!,
grant_type: 'refresh_token',
refresh_token: token.refresh_token as string,
}),
}
);
if (!refreshResponse.ok) {
throw new Error('Failed to refresh token');
}
const tokensOrError = await refreshResponse.json();
if (!refreshResponse.ok) throw tokensOrError;
const newTokens = tokensOrError as {
access_token: string;
expires_in: number;
refresh_token?: string;
};
return {
...token,
access_token: newTokens.access_token,
expires_at: Math.floor(Date.now() / 1000 + newTokens.expires_in),
// Some providers only issue refresh tokens once, so preserve if we did not get a new one
refresh_token: newTokens.refresh_token
? newTokens.refresh_token
: token.refresh_token,
};
} catch (error) {
console.error('Error refreshing access_token', error);
// If we fail to refresh the token, return an error so we can handle it on the page
token.error = 'RefreshTokenError';
return token;
}
}
},
async session(params) {
const { session, token } = params;
return { ...session, ...token };
},
},
});
declare module 'next-auth' {
interface Session {
access_token: string;
expires_in: number;
id_token?: string;
expires_at: number;
refresh_token?: string;
refresh_token_id?: string;
error?: 'RefreshTokenError';
scope: string;
token_type: string;
userId: string;
provider: string;
type: string;
providerAccountId: string;
}
}
declare module 'next-auth' {
interface JWT {
access_token: string;
expires_in: number;
id_token?: string;
expires_at: number;
refresh_token?: string;
refresh_token_id?: string;
error?: 'RefreshTokenError';
scope: string;
token_type: string;
userId: string;
provider: string;
type: string;
providerAccountId: string;
}
}
*
*
*
*/
export default function FusionAuth<P extends FusionAuthProfile>(
// tenantId only needed if there is more than one tenant configured on the server
Expand All @@ -118,6 +282,9 @@ export default function FusionAuth<P extends FusionAuthProfile>(
id: "fusionauth",
name: "FusionAuth",
type: "oidc",
issuer: options.issuer,
clientId: options.clientId,
clientSecret: options.clientSecret,
wellKnown: options?.tenantId
? `${options.issuer}/.well-known/openid-configuration?tenantId=${options.tenantId}`
: `${options.issuer}/.well-known/openid-configuration`,
Expand Down

0 comments on commit d247690

Please sign in to comment.