Skip to content

Commit

Permalink
Merge branch 'feature/keycloak' into feature/snyk
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinOomenTheDeveloper committed Jun 18, 2024
2 parents b0e9b84 + 7248581 commit e38dcf0
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 31 deletions.
37 changes: 37 additions & 0 deletions src/app/api/auth/[...nextauth]/authOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Token } from "@/types/next-auth";
import { AuthOptions } from "next-auth";
import KeycloakProvider from "next-auth/providers/keycloak";

export const authOptions: AuthOptions = {
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID as string,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET as string,
issuer: process.env.KEYCLOAK_URL,
wellKnown: `${process.env.KEYCLOAK_URL}/.well-known/openid-configuration`
//idToken: true
}),
],
session: {
strategy: "jwt",
},
callbacks: {
async jwt({ token, user, account }) {
if (account) {
token.accessToken = account.access_token;
token.refreshToken = account.refresh_token;
token.accessTokenExpired = account.expires_at! * 1000;
token.user = user;

return token;
}
return token;
},
async session({ session, token }) {
session.token = token as unknown as Token;

return session;
},
},
secret: process.env.NEXTAUTH_SECRET,
};
6 changes: 6 additions & 0 deletions src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions";
import NextAuth from "next-auth";

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };
20 changes: 20 additions & 0 deletions src/app/api/getSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*import { getServerSession } from "next-auth/next";
import { authOptions } from "./auth/[...nextauth]/authOptions";
export async function getSession(req) {
try {
const session = await getServerSession(authOptions, req);
if (!session) {
return null;
}
return {
user: session.user,
accessToken: session.accessToken,
};
} catch (error) {
console.error("Error fetching session:", error);
return null;
}
}*/
27 changes: 27 additions & 0 deletions src/app/authenticate/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

'use client';
import { getSession, signIn } from "next-auth/react";
import { useEffect } from "react";

export default async function Home(req) {
const session = await getSession({ req });

const accessToken = session.token.accessToken;
console.log(accessToken);
//const { data: session } = useSession();

return (
<div>
{ session ?
<button>
{session.token.accessToken}
Logout
</button>
:
<button onClick={() => signIn("keycloak")}>
Login
</button>
}
</div>
);
}
6 changes: 5 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import SessionProviderWrapper from "../components/SessionProviderWrapper";
import { ReactNode } from "react";

const inter = Inter({ subsets: ["latin"] });

Expand All @@ -16,7 +18,9 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body className={inter.className}>
<SessionProviderWrapper>{children}</SessionProviderWrapper>
</body>
</html>
);
}
11 changes: 0 additions & 11 deletions src/app/page/layout.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions src/app/page/page.tsx

This file was deleted.

69 changes: 69 additions & 0 deletions src/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*import NextAuth from "next-auth";
import { JWT } from "next-auth/jwt";
import KeycloakProvider from "next-auth/providers/keycloak";
const params = {
client_id: process.env.KEYCLOAK_CLIENT_ID,
client_secret: process.env.KEYCLOAK_CLIENT_SECRET,
grant_type: "refresh_token",
}
function refreshAccessToken(refresh_token: string){
return fetch(`${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token`, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
...params,
refresh_token
}),
method: "POST"
});
}
export const { auth, handlers: { GET, POST } , signIn, signOut } = NextAuth({
session: {
strategy: "jwt",
maxAge: 60 * 30
},
callbacks: {
async session({ session, token }){
session.idToken = token.idToken
session.refreshToken = token.refreshToken
return session;
},
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;
token.userId = account.userId;
return token;
}
if(Date.now() < (token.expiresAt!)){
return token;
}
try{
const response = await refreshAccessToken(token.refreshToken);
if(!response.ok) throw new Error();
const newToken = await response.json();
const updatedToken: JWT = {
...token,
idToken: newToken.id_token,
accessToken: newToken.access_token,
expiresAt: newToken.expires_at
}
return updatedToken;
}
catch(error){
return { ...token, error: "RefreshAccessTokenError" }
}
}
},
providers: [KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET,
issuer: process.env.KEYCLOAK_URL,
})]
})*/
17 changes: 17 additions & 0 deletions src/components/Authentication.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client";

import { signIn, signOut, useSession } from "next-auth/react";

export default function AuthButton() {
const { data: session } = useSession();

return (
<div>
{!session ? (
<button onClick={() => signIn("keycloak")}>Sign in</button>
) : (
<button onClick={() => signOut()}>Sign out</button>
)}
</div>
);
}
8 changes: 8 additions & 0 deletions src/components/SessionProviderWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"use client";

import { SessionProvider } from "next-auth/react";
import { ReactNode } from "react";

export default function SessionProviderWrapper({ children }: { children: ReactNode }) {
return <SessionProvider>{children}</SessionProvider>;
}
11 changes: 11 additions & 0 deletions src/components/utils/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import axios, { AxiosInstance } from 'axios';

const apiClient = (token: string | null): AxiosInstance => {
return axios.create({
headers: {
Authorization: token ? `Bearer ${token}` : '',
},
});
};

export default apiClient;
4 changes: 2 additions & 2 deletions src/types/next-auth.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import NextAuth from "next-auth";
import nextAuth from "next-auth";

declare module "next-auth" {
interface Session {
token: Token;
Expand Down
8 changes: 5 additions & 3 deletions src/types/node-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
declare namespace NodeJS {
/*declare namespace NodeJS {
export interface ProcessEnv {
AUTH_URL: string
AUTH_SECRET: string
KEYCLOAK_CLIENT_ID: string
KEYCLOAK_CLIENT_SECRET: string
KEYCLOAK_ISSUER: string
KEYCLOAK_URL: string
MUSIC_API_URL: string
SESSION_API_URL: string
}
}
}*/
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"compilerOptions": {
"typeRoots": ["./types", "./node_modules/@types"],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
Expand Down

0 comments on commit e38dcf0

Please sign in to comment.