Skip to content

Commit

Permalink
rebase fix
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikmonsen committed May 30, 2024
1 parent ab90b2e commit bf2fc68
Show file tree
Hide file tree
Showing 18 changed files with 281 additions and 134 deletions.
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
NEXT_PUBLIC_BASE_PATH=/hugin
CATALOGUE_API_PATH=http://localhost:8087/bikube
CATALOGUE_API_PATH=http://localhost:8087/bikube
KEYCLOAK_CLIENT_ID=your-client-id
KEYCLOAK_CLIENT_SECRET=secret
KEYCLOAK_ISSUER=https://your-keycloak-domain.com/realms/your-realm
NEXTAUTH_URL=http://localhost:3000/hugin/api/auth
NEXTAUTH_SECRET=secret
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ For å kjøre lokalt må du sette de nødvendige miljøvariablene:
cp .env.example .env.local
```

| Variabelnavn | Standardverdi | Beskrivelse |
|--------------------|------------------------------|----------------------------------------------------------------------------------------------------------------------|
| BASE_PATH | /hugin | Base path for applikasjonen |
| CATALOGUE_API_PATH | http://localhost:8087/bikube | Sti til [katalog APIet ](https://github.com/NationalLibraryOfNorway/bikube)<br/>Må starte med http:// eller https:// |

| Variabelnavn | Standardverdi | Beskrivelse |
|------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| NEXT_PUBLIC_BASE_PATH | /hugin | Base path for applikasjonen |
| CATALOGUE_API_PATH | http://localhost:8087/bikube | Sti til [katalog APIet ](https://github.com/NationalLibraryOfNorway/bikube)<br/>Må starte med http:// eller https:// |
| KEYCLOAK_CLIENT_ID | _N/A_ | Klient ID |
| KEYCLOAK_CLIENT_SECRET | _N/A_ | Klienthemmelighet |
| KEYCLOAK_ISSUER | _N/A_ | Utsteder-URI. Må inneholde realm, f.eks: https://my-keycloak-domain.com/realms/My_Realm |
| NEXTAUTH_URL | http://localhost:3000/hugin/api/auth | URL til siden, f.eks. http://localhost:3000. Når man bruker basePath må man spesifisere hele API-routen: http://localhost:3000/hugin/api/auth |
| NEXTAUTH_SECRET | _N/A_ | Kan genereres med `openssl rand -base64 32` |

Deretter kan du kjøre følgende kommandoer:
```bash
Expand Down
7 changes: 1 addition & 6 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@ import {withSentryConfig} from "@sentry/nextjs";
const nextConfig = {
output: "standalone",
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
env: {
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
KEYCLOAK_ISSUER: process.env.KEYCLOAK_ISSUER,
APP_URL: process.env.APP_URL,
},
async rewrites() {
return [
{
source: `${process.env.NEXT_PUBLIC_BASE_PATH}/api/:path*`,
source: `${process.env.NEXT_PUBLIC_BASE_PATH}/api/catalogue/:path*`,
destination: `${process.env.CATALOGUE_API_PATH}/:path*`,
basePath: false
},
Expand Down
105 changes: 105 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 3 additions & 70 deletions src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,6 @@
/* eslint-disable @typescript-eslint/naming-convention,@typescript-eslint/no-unsafe-assignment */
import NextAuth, {AuthOptions, TokenSet} from 'next-auth';
import KeycloakProvider from 'next-auth/providers/keycloak';
import {JWT} from 'next-auth/jwt';

export const authOptions: AuthOptions = {
// debug: true,
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID ?? '',
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET ?? '',
issuer: process.env.KEYCLOAK_ISSUER
})
],
session: {
maxAge: 5 * 60
},
callbacks: {
async jwt({ token, account }) {
if (account) {
token.idToken = account.id_token!;
token.accessToken = account.access_token!;
token.refreshToken = account.refresh_token!;
token.expiresAt = account.expires_at!;
return token;
}
if (Date.now() < token.expiresAt * 1000 - 10 * 1000) {
return token;
}
try {
const response = await requestRefreshOfAccessToken(token);
const tokens: TokenSet = await response.json();

if (!response.ok) throw tokens;

return {
...token,
accessToken: tokens.access_token!,
expiresAt: Math.floor(Date.now() / 1000 + (tokens.expires_in as number)),
refreshToken: tokens.refresh_token ?? token.refreshToken,
};
} catch (error) {
console.error('Error refreshing access token', error);
return {...token, error: 'RefreshAccessTokenError' as const};
}
},
// eslint-disable-next-line @typescript-eslint/require-await
async session({ session, token }) {
if (token.accessToken) {
session.idToken = token.idToken;
session.accessToken = token.accessToken;
}
session.error = token.error;
return session;
}
}
};

async function requestRefreshOfAccessToken(token: JWT) {
return await fetch(`${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token`, {
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
client_id: process.env.KEYCLOAK_CLIENT_ID,
client_secret: process.env.KEYCLOAK_CLIENT_SECRET,
grant_type: 'refresh_token',
refresh_token: token.refreshToken,
}),
method: 'POST'
});
}
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import NextAuth from 'next-auth';
import {authOptions} from '@/app/lib/auth';

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
8 changes: 4 additions & 4 deletions src/app/api/auth/federated-logout/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ function handleEmptyToken() {
return NextResponse.json(response, responseHeaders);
}

function sendEndSessionEndpointToURL(token: JWT) {
const endSessionEndPoint = new URL(
function endKeycloakSession(token: JWT) {
const keycloakLogoutURL = new URL(
`${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/logout`
);
const params: Record<string, string> = logoutParams(token);
const endSessionParams = new URLSearchParams(params);
const response = { url: `${endSessionEndPoint.href}/?${endSessionParams.toString()}` };
const response = { url: `${keycloakLogoutURL.href}/?${endSessionParams.toString()}` };
return NextResponse.json(response);
}

export async function GET(req: NextRequest) {
try {
const token = await getToken({ req });
if (token) {
return sendEndSessionEndpointToURL(token);
return endKeycloakSession(token);
}
return handleEmptyToken();
} catch (error) {
Expand Down
17 changes: 0 additions & 17 deletions src/app/api/logout/page.tsx

This file was deleted.

69 changes: 69 additions & 0 deletions src/app/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint-disable @typescript-eslint/naming-convention,@typescript-eslint/no-unsafe-assignment */
import {AuthOptions, TokenSet} from 'next-auth';
import KeycloakProvider from 'next-auth/providers/keycloak';
import {JWT} from 'next-auth/jwt';

export const authOptions: AuthOptions = {
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID ?? '',
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET ?? '',
issuer: process.env.KEYCLOAK_ISSUER
})
],
session: {
maxAge: 5 * 60
},
callbacks: {
async jwt({ token, account }) {
if (account) {
token.idToken = account.id_token!;
token.accessToken = account.access_token!;
token.refreshToken = account.refresh_token!;
token.expiresAt = account.expires_at!;
return token;
}
if (Date.now() < token.expiresAt * 1000 - 10 * 1000) {
return token;
}
try {
const response = await requestRefreshOfAccessToken(token);
const tokens: TokenSet = await response.json();

if (!response.ok) throw tokens;

return {
...token,
accessToken: tokens.access_token!,
expiresAt: Math.floor(Date.now() / 1000 + (tokens.expires_in as number)),
refreshToken: tokens.refresh_token ?? token.refreshToken,
};
} catch (error) {
console.error('Error refreshing access token', error);
return {...token, error: 'RefreshAccessTokenError' as const};
}
},
// eslint-disable-next-line @typescript-eslint/require-await
async session({ session, token }) {
if (token.accessToken) {
session.idToken = token.idToken;
session.accessToken = token.accessToken;
}
session.error = token.error;
return session;
}
}
};

async function requestRefreshOfAccessToken(token: JWT) {
return await fetch(`${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token`, {
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
client_id: process.env.KEYCLOAK_CLIENT_ID,
client_secret: process.env.KEYCLOAK_CLIENT_SECRET,
grant_type: 'refresh_token',
refresh_token: token.refreshToken,
}),
method: 'POST'
});
}
11 changes: 7 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import SearchBar from '@/components/SearchBar';
import Image from 'next/image';
import {Providers} from '@/app/providers';

export default function Home() {
return (
<div className="w-96 flex flex-col items-center justify-start">
<Image className="m-5" src="/hugin/hugin.svg" alt="Hugin logo" width={128} height={128}/>
<SearchBar />
</div>
<Providers>
<div className="w-96 flex flex-col items-center justify-start">
<Image className="m-5" src="/hugin/hugin.svg" alt="Hugin logo" width={128} height={128}/>
<SearchBar/>
</div>
</Providers>
);
}
Loading

0 comments on commit bf2fc68

Please sign in to comment.