From f5efb8640595e04be0da3fba151eae3c8b422ba3 Mon Sep 17 00:00:00 2001 From: pnzrr Date: Tue, 23 Jul 2024 22:28:30 -0600 Subject: [PATCH 01/25] add token to the react app --- .github/workflows/nextjs.yml | 4 +- .github/workflows/react.yml | 90 ++++++++++++ README.md | 15 +- frameworks/nextjs/README.md | 8 +- .../components/footer-links.components.tsx | 3 +- frameworks/reactjs/.gitignore | 3 +- frameworks/reactjs/README.md | 8 +- frameworks/reactjs/package-lock.json | 137 +++++++++++------- frameworks/reactjs/package.json | 3 + frameworks/reactjs/src/App.tsx | 52 ++----- frameworks/reactjs/src/Auth.tsx | 2 + .../components/footer-links.components.tsx | 52 +++++++ .../src/components/token.component.tsx | 75 ++++++++++ frameworks/reactjs/src/index.tsx | 10 +- 14 files changed, 345 insertions(+), 117 deletions(-) create mode 100644 .github/workflows/react.yml create mode 100644 frameworks/reactjs/src/components/footer-links.components.tsx create mode 100644 frameworks/reactjs/src/components/token.component.tsx diff --git a/.github/workflows/nextjs.yml b/.github/workflows/nextjs.yml index 8ee99b6..9b509bd 100644 --- a/.github/workflows/nextjs.yml +++ b/.github/workflows/nextjs.yml @@ -1,8 +1,8 @@ -name: Deploy to Vercel +name: Deploy Next.js Example to Vercel env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_NEXTJS_PROJECT_ID }} VERCEL_TOKEN: ${{ secrets.VERCEL_DEPLOYMENT_TOKEN }} on: push: diff --git a/.github/workflows/react.yml b/.github/workflows/react.yml new file mode 100644 index 0000000..47086ff --- /dev/null +++ b/.github/workflows/react.yml @@ -0,0 +1,90 @@ +name: Deploy React Example to Vercel + +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_REACT_PROJECT_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_DEPLOYMENT_TOKEN }} +on: + push: + branches: + - main + paths: + - "frameworks/reactjs/**" + pull_request: + branches: + - main + paths: + - "frameworks/reactjs/**" + +jobs: + deploy-preview: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + + - name: Install dependencies + run: npm install + working-directory: ./frameworks/reactjs + + - name: Build project + run: npm run build + working-directory: ./frameworks/reactjs + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=$VERCEL_TOKEN + working-directory: ./frameworks/reactjs + + - name: Build Project Artifacts + run: vercel build --token=$VERCEL_TOKEN + working-directory: ./frameworks/reactjs + + - name: Deploy Project Artifacts to Vercel + run: vercel deploy --prebuilt --token=$VERCEL_TOKEN + working-directory: ./frameworks/reactjs + + deploy-prod: + if: github.event_name == 'push' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + + - name: Install dependencies + run: npm install + working-directory: ./frameworks/reactjs + + - name: Build project + run: npm run build + working-directory: ./frameworks/reactjs + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=production --token=$VERCEL_TOKEN + working-directory: ./frameworks/reactjs + + - name: Build Project Artifacts + run: vercel build --prod --token=$VERCEL_TOKEN + working-directory: ./frameworks/reactjs + + - name: Deploy Project Artifacts to Vercel + run: vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN + working-directory: ./frameworks/reactjs diff --git a/README.md b/README.md index ce50867..8c3c4de 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ This is a repo for code examples showing how to integrate Keycloak with various ## Frameworks -- [ReactJS](./frameworks/reactjs/) -- [NextJs](./frameworks/nextjs/) -- [Nuxt](./frameworks/nuxt/) -- [Vue](./frameworks/vue/) -- [Django](./frameworks/django/) -- [Remix](./frameworks/remix/) -- [SpringBoot](./frameworks/spring-boot-keycloak/) \ No newline at end of file +| Framework | Code | Live | +| --------------------- | :----------------------------------------: | :------------------------------------------------------: | +| React | [🧑‍💻📁](./frameworks/reactjs/) | [👩‍💻:shipit:](https://phasetwo-react-example.vercel.app) | +| Next.js | [🧑‍💻📁](./frameworks/nextjs/) | [👩‍💻:shipit:](https://phasetwo-nextjs-example.vercel.app) | +| Nuxt (keycloak-js) | [🧑‍💻📁](./frameworks/nuxt/keycloak-js/) | 👩‍💻:hammer_and_pick: | +| Nuxt (oidc-client-ts) | [🧑‍💻📁](./frameworks/nuxt/oidc-client-ts/) | 👩‍💻:hammer_and_pick: | +| Django | [🧑‍💻📁](./frameworks/django/) | 👩‍💻:hammer_and_pick: | +| SpringBoot + Angular | [🧑‍💻📁](./frameworks/spring-boot-keycloak/) | 👩‍💻:hammer_and_pick: | diff --git a/frameworks/nextjs/README.md b/frameworks/nextjs/README.md index 5bb9f8c..5faee79 100644 --- a/frameworks/nextjs/README.md +++ b/frameworks/nextjs/README.md @@ -28,10 +28,10 @@ All Auth related items are in [Auth.tsx]("./src/Auth.tsx"). This example leverag In the project directory, you can run: -### `npm run dev` +`npm run dev` + +Runs the app in the development mode. -Runs the app in the development mode.\ Open [http://localhost:3000](http://localhost:3000) to view it in the browser. -The page will reload if you make edits.\ -You will also see any lint errors in the console. +The page will reload if you make edits. You will also see any lint errors in the console. diff --git a/frameworks/nextjs/src/components/footer-links.components.tsx b/frameworks/nextjs/src/components/footer-links.components.tsx index db0bd86..e38dbbc 100644 --- a/frameworks/nextjs/src/components/footer-links.components.tsx +++ b/frameworks/nextjs/src/components/footer-links.components.tsx @@ -1,5 +1,4 @@ import { Icon } from "@iconify/react"; -import Link from "next/link"; const LinkContainer = ({ children }: { children: React.ReactNode }) => { return ( @@ -11,7 +10,7 @@ const LinkContainer = ({ children }: { children: React.ReactNode }) => { export const FooterLinks = () => { return ( -
+
=16" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -4030,6 +4054,15 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -11532,9 +11565,12 @@ } }, "node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } }, "node_modules/kind-of": { "version": "6.0.3", @@ -12267,6 +12303,11 @@ "node": ">=12.13.0" } }, + "node_modules/oidc-client-ts/node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -14963,12 +15004,9 @@ } }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -14976,22 +15014,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -18772,6 +18794,21 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, + "@iconify/react": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@iconify/react/-/react-5.0.1.tgz", + "integrity": "sha512-octpAJRtHZLLS1o6fmz2Ek2Rfwx75kVg48MZyGTqL3QqoxRddEsuLqOt6ADDhRosmlrYnIrVL+7obo1bz2ikNw==", + "dev": true, + "requires": { + "@iconify/types": "^2.0.0" + } + }, + "@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -19996,6 +20033,15 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "@types/jsonwebtoken": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -25449,9 +25495,9 @@ } }, "jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==" }, "kind-of": { "version": "6.0.3", @@ -25985,6 +26031,13 @@ "requires": { "crypto-js": "^4.1.1", "jwt-decode": "^3.1.2" + }, + "dependencies": { + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + } } }, "on-finished": { @@ -27672,27 +27725,9 @@ } }, "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" }, "send": { "version": "0.18.0", diff --git a/frameworks/reactjs/package.json b/frameworks/reactjs/package.json index 187917a..9e1d9ab 100644 --- a/frameworks/reactjs/package.json +++ b/frameworks/reactjs/package.json @@ -11,6 +11,7 @@ "@types/node": "^16.18.38", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", + "jwt-decode": "^4.0.0", "oidc-client-ts": "^2.2.4", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -44,6 +45,8 @@ ] }, "devDependencies": { + "@iconify/react": "^5.0.1", + "@types/jsonwebtoken": "^9.0.6", "prettier": "^3.0.0", "prettier-plugin-tailwindcss": "^0.3.0", "tailwindcss": "^3.3.2" diff --git a/frameworks/reactjs/src/App.tsx b/frameworks/reactjs/src/App.tsx index af25ae4..56d7c81 100644 --- a/frameworks/reactjs/src/App.tsx +++ b/frameworks/reactjs/src/App.tsx @@ -1,6 +1,8 @@ import "./App.css"; +import { Icon } from "@iconify/react"; import Auth from "./Auth"; +import { FooterLinks } from "./components/footer-links.components"; function App() { return ( @@ -14,12 +16,12 @@ function App() { alt="Gradient Background" /> -
+
Phase Two @@ -28,55 +30,19 @@ function App() { target="_blank" rel="noreferrer" > -

- React App Example +

+ +

- ); } diff --git a/frameworks/reactjs/src/Auth.tsx b/frameworks/reactjs/src/Auth.tsx index a3bbf56..ada9226 100644 --- a/frameworks/reactjs/src/Auth.tsx +++ b/frameworks/reactjs/src/Auth.tsx @@ -1,4 +1,5 @@ import { useAuth } from "react-oidc-context"; +import { Token } from "./components/token.component"; const Auth = () => { const auth = useAuth(); @@ -58,6 +59,7 @@ const Auth = () => { > Log out +
); } diff --git a/frameworks/reactjs/src/components/footer-links.components.tsx b/frameworks/reactjs/src/components/footer-links.components.tsx new file mode 100644 index 0000000..e38dbbc --- /dev/null +++ b/frameworks/reactjs/src/components/footer-links.components.tsx @@ -0,0 +1,52 @@ +import { Icon } from "@iconify/react"; + +const LinkContainer = ({ children }: { children: React.ReactNode }) => { + return ( +
+ {children} +
+ ); +}; + +export const FooterLinks = () => { + return ( + + ); +}; diff --git a/frameworks/reactjs/src/components/token.component.tsx b/frameworks/reactjs/src/components/token.component.tsx new file mode 100644 index 0000000..886976f --- /dev/null +++ b/frameworks/reactjs/src/components/token.component.tsx @@ -0,0 +1,75 @@ +// import jwt from "jsonwebtoken"; +import { useAuth } from "react-oidc-context"; +import { jwtDecode } from "jwt-decode"; + +const TextAreaClasses = + "block w-full rounded-md border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 bg-purple-200/50"; + +function stringifyToken(token: any) { + return JSON.stringify(jwtDecode(token), null, 2); +} + +export const Token = () => { + const auth = useAuth(); + + if (auth.isLoading || auth.error || !auth.isAuthenticated) { + return null; + } + + if (auth.isAuthenticated) { + return ( +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ ); + } + + return null; +}; diff --git a/frameworks/reactjs/src/index.tsx b/frameworks/reactjs/src/index.tsx index 1e964f0..8c6a726 100644 --- a/frameworks/reactjs/src/index.tsx +++ b/frameworks/reactjs/src/index.tsx @@ -4,14 +4,16 @@ import "./index.css"; import App from "./App"; import { AuthProvider } from "react-oidc-context"; -const authServerUrl = "https://euc1.auth.ac/auth/"; -const realm = "shared-deployment-001"; -const client = "reg-example-1"; +// CHANGE authServerUrl to your Auth Server URL +const authServerUrl = "https://app.phasetwo.io/auth/"; +const realm = "p2examples"; +const client = "reactjs-example"; const oidcConfig = { authority: `${authServerUrl}realms/${realm}`, client_id: client, - redirect_uri: "http://localhost:3000/authenticated", + // CHANGE redirect_uri to your app url + redirect_uri: "https://phasetwo-react-example.vercel.app/", onSigninCallback: (args: any) => window.history.replaceState({}, document.title, window.location.pathname), }; From 2f5a104d0083a53a8c9dbb47d6031868d352bed5 Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Tue, 23 Jul 2024 22:34:40 -0600 Subject: [PATCH 02/25] update icons --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8c3c4de..b9d4bf5 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ This is a repo for code examples showing how to integrate Keycloak with various ## Frameworks -| Framework | Code | Live | -| --------------------- | :----------------------------------------: | :------------------------------------------------------: | -| React | [🧑‍💻📁](./frameworks/reactjs/) | [👩‍💻:shipit:](https://phasetwo-react-example.vercel.app) | -| Next.js | [🧑‍💻📁](./frameworks/nextjs/) | [👩‍💻:shipit:](https://phasetwo-nextjs-example.vercel.app) | -| Nuxt (keycloak-js) | [🧑‍💻📁](./frameworks/nuxt/keycloak-js/) | 👩‍💻:hammer_and_pick: | -| Nuxt (oidc-client-ts) | [🧑‍💻📁](./frameworks/nuxt/oidc-client-ts/) | 👩‍💻:hammer_and_pick: | -| Django | [🧑‍💻📁](./frameworks/django/) | 👩‍💻:hammer_and_pick: | -| SpringBoot + Angular | [🧑‍💻📁](./frameworks/spring-boot-keycloak/) | 👩‍💻:hammer_and_pick: | +| Framework | Code | Live | +| --------------------- | :----------------------------------------: | :------------------------------------------------: | +| React | [🧑‍💻📁](./frameworks/reactjs/) | [👩‍💻🚀](https://phasetwo-react-example.vercel.app) | +| Next.js | [🧑‍💻📁](./frameworks/nextjs/) | [👩‍💻🚀](https://phasetwo-nextjs-example.vercel.app) | +| Nuxt (keycloak-js) | [🧑‍💻📁](./frameworks/nuxt/keycloak-js/) | 👩‍💻⚒️ | +| Nuxt (oidc-client-ts) | [🧑‍💻📁](./frameworks/nuxt/oidc-client-ts/) | 👩‍💻⚒️ | +| Django | [🧑‍💻📁](./frameworks/django/) | 👩‍💻⚒️ | +| SpringBoot + Angular | [🧑‍💻📁](./frameworks/spring-boot-keycloak/) | 👩‍💻⚒️ | From 5748ec38bdf2a618e4d207d44fff95c7d1780af0 Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Thu, 25 Jul 2024 16:06:26 -0600 Subject: [PATCH 03/25] add next.js env example --- frameworks/nextjs/.env.example | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 frameworks/nextjs/.env.example diff --git a/frameworks/nextjs/.env.example b/frameworks/nextjs/.env.example new file mode 100644 index 0000000..42494c7 --- /dev/null +++ b/frameworks/nextjs/.env.example @@ -0,0 +1,9 @@ +# Local or Deployed URL +NEXTAUTH_URL=http://localhost:3000 +# Keycloak client ID or "resource" in Keycloak +KEYCLOAK_ID=nextjs-example +# Client secrets are provided by the client in Keycloak. These two should be the same and are both needed. +NEXTAUTH_SECRET= +KEYCLOAK_SECRET= +# Keycloak issuer URL +KEYCLOAK_ISSUER=http:///auth/realms/ \ No newline at end of file From 0dd1ad2ecff6390d0c6fb3f81d05982a873201de Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Thu, 25 Jul 2024 16:07:03 -0600 Subject: [PATCH 04/25] update remix app to show session information --- frameworks/remix/.env.example | 10 +++++ frameworks/remix/app/components/user.tsx | 38 ++++++++++++++----- frameworks/remix/app/routes/_index.tsx | 18 +++++---- .../remix/app/services/keycloak.server.ts | 19 ++++------ frameworks/remix/package-lock.json | 22 +++++++++++ frameworks/remix/package.json | 1 + 6 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 frameworks/remix/.env.example diff --git a/frameworks/remix/.env.example b/frameworks/remix/.env.example new file mode 100644 index 0000000..5509993 --- /dev/null +++ b/frameworks/remix/.env.example @@ -0,0 +1,10 @@ +# Keycloak issuer URL; i.e. usw2.auth.ac/auth +KEYCLOAK_ISSUER_DOMAIN=/auth +# Keycloak realm; i.e. myrealm +KEYCLOAK_REALM= +# Keycloak client ID or "resource" in Keycloak +KEYCLOAK_CLIENT_ID=remix-example +# Client secrets are provided by the client in Keycloak. +KEYCLOAK_CLIENT_SECRET= +# Callback URL for Keycloak, where Keycloak will redirect to after authentication. i.e. http://localhost:3000/auth/callback/keycloak +KEYCLOAK_CALLBACK_URL=http:///auth/keycloak/callback \ No newline at end of file diff --git a/frameworks/remix/app/components/user.tsx b/frameworks/remix/app/components/user.tsx index 09b7ad4..aa34dab 100644 --- a/frameworks/remix/app/components/user.tsx +++ b/frameworks/remix/app/components/user.tsx @@ -1,14 +1,15 @@ +import { User as UserType } from "~/services/auth.server"; import { LoginButton, LogoutButton } from "./buttons"; -interface User { +interface UserArgs { status: boolean; - user?: { - name?: string; - email?: string; - } + user?: UserType; } -export const User = ({ status, user }: User) => { +const TextAreaClasses = + "block w-full rounded-md border-0 py-1.5 px-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 bg-purple-200/50"; + +export const User = ({ status, user }: UserArgs) => { let content; if (!status) { @@ -20,15 +21,34 @@ export const User = ({ status, user }: User) => { ); } - if (status) { + if (status && user) { + const profile = user.__json; content = (
Authenticated
-
{user?.email}
-
{user?.name}
+
{profile?.email}
+
{profile?.name}
+
+
+ + + +
+
); } diff --git a/frameworks/remix/app/routes/_index.tsx b/frameworks/remix/app/routes/_index.tsx index 196babd..e9e2d35 100644 --- a/frameworks/remix/app/routes/_index.tsx +++ b/frameworks/remix/app/routes/_index.tsx @@ -2,14 +2,18 @@ import { User } from "~/components/user"; import { useLoaderData } from "@remix-run/react"; import { authenticator } from "~/services/auth.server"; import { LoaderFunctionArgs, json } from "@remix-run/node"; +import { Icon } from "@iconify/react"; export async function loader({ request }: LoaderFunctionArgs) { + console.log("🚀 ~ loader ~ request:", authenticator); + const user = await authenticator.isAuthenticated(request); return json(user); } export default function Index() { const authenticatedUser = useLoaderData(); + console.log("🚀 ~ Index ~ authenticatedUser:", authenticatedUser); return (
@@ -21,12 +25,12 @@ export default function Index() { alt="Gradient Background" /> -
+
Phase Two @@ -35,18 +39,16 @@ export default function Index() { target="_blank" rel="noreferrer" > -

- Remix App Example +

+ +

- +
diff --git a/frameworks/remix/app/services/keycloak.server.ts b/frameworks/remix/app/services/keycloak.server.ts index 9da2914..814b59a 100644 --- a/frameworks/remix/app/services/keycloak.server.ts +++ b/frameworks/remix/app/services/keycloak.server.ts @@ -1,15 +1,12 @@ import { KeycloakStrategy } from "remix-keycloak"; const kcConfig = { - useSSL: true, - domain: "usw2.auth.ac/auth", - realm: "shared-deployment-001", - clientID: "reg-example-1", - clientSecret: "CLIENT_SECRET", - callbackURL: "http://localhost:3000/auth/keycloak/callback", -} + useSSL: true, + domain: process.env.KEYCLOAK_ISSUER_DOMAIN, + realm: process.env.KEYCLOAK_REALM, + clientID: process.env.KEYCLOAK_CLIENT_ID, + clientSecret: process.env.KEYCLOAK_CLIENT_SECRET, + callbackURL: process.env.KEYCLOAK_CALLBACK_URL, +}; -export default new KeycloakStrategy( - kcConfig, - ({ profile }) => profile -); +export default new KeycloakStrategy(kcConfig, ({ profile }) => profile); diff --git a/frameworks/remix/package-lock.json b/frameworks/remix/package-lock.json index 6b1e0a8..c4e52be 100644 --- a/frameworks/remix/package-lock.json +++ b/frameworks/remix/package-lock.json @@ -16,6 +16,7 @@ "remix-keycloak": "^2.0.4" }, "devDependencies": { + "@iconify/react": "^5.0.1", "@remix-run/dev": "^2.9.0", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", @@ -1199,6 +1200,27 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "node_modules/@iconify/react": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@iconify/react/-/react-5.0.1.tgz", + "integrity": "sha512-octpAJRtHZLLS1o6fmz2Ek2Rfwx75kVg48MZyGTqL3QqoxRddEsuLqOt6ADDhRosmlrYnIrVL+7obo1bz2ikNw==", + "dev": true, + "dependencies": { + "@iconify/types": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/cyberalien" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", diff --git a/frameworks/remix/package.json b/frameworks/remix/package.json index 620baf1..cc77de4 100644 --- a/frameworks/remix/package.json +++ b/frameworks/remix/package.json @@ -22,6 +22,7 @@ "remix-keycloak": "^2.0.4" }, "devDependencies": { + "@iconify/react": "^5.0.1", "@remix-run/dev": "^2.9.0", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", From 4e0d6489a1817bf2c1323debde15506fa4c010c3 Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Thu, 25 Jul 2024 16:07:09 -0600 Subject: [PATCH 05/25] add class for react --- frameworks/reactjs/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameworks/reactjs/src/App.tsx b/frameworks/reactjs/src/App.tsx index 56d7c81..fcae3a6 100644 --- a/frameworks/reactjs/src/App.tsx +++ b/frameworks/reactjs/src/App.tsx @@ -6,7 +6,7 @@ import { FooterLinks } from "./components/footer-links.components"; function App() { return ( -
+
From d25f05645ccbe9bc082e5cd47a68c5bb43b87efc Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Thu, 25 Jul 2024 16:12:33 -0600 Subject: [PATCH 06/25] add workflow file --- .github/workflows/remix.yml | 90 ++++++++++++++++++++++++++ frameworks/remix/.gitignore | 1 + frameworks/remix/app/routes/_index.tsx | 3 - 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/remix.yml diff --git a/.github/workflows/remix.yml b/.github/workflows/remix.yml new file mode 100644 index 0000000..0e8d3ef --- /dev/null +++ b/.github/workflows/remix.yml @@ -0,0 +1,90 @@ +name: Deploy React Example to Vercel + +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_REMIX_PROJECT_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_DEPLOYMENT_TOKEN }} +on: + push: + branches: + - main + paths: + - "frameworks/remix/**" + pull_request: + branches: + - main + paths: + - "frameworks/remix/**" + +jobs: + deploy-preview: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + + - name: Install dependencies + run: npm install + working-directory: ./frameworks/remix + + - name: Build project + run: npm run build + working-directory: ./frameworks/remix + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=$VERCEL_TOKEN + working-directory: ./frameworks/remix + + - name: Build Project Artifacts + run: vercel build --token=$VERCEL_TOKEN + working-directory: ./frameworks/remix + + - name: Deploy Project Artifacts to Vercel + run: vercel deploy --prebuilt --token=$VERCEL_TOKEN + working-directory: ./frameworks/remix + + deploy-prod: + if: github.event_name == 'push' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + + - name: Install dependencies + run: npm install + working-directory: ./frameworks/remix + + - name: Build project + run: npm run build + working-directory: ./frameworks/remix + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=production --token=$VERCEL_TOKEN + working-directory: ./frameworks/remix + + - name: Build Project Artifacts + run: vercel build --prod --token=$VERCEL_TOKEN + working-directory: ./frameworks/remix + + - name: Deploy Project Artifacts to Vercel + run: vercel deploy --prebuilt --prod --token=$VERCEL_TOKEN + working-directory: ./frameworks/remix diff --git a/frameworks/remix/.gitignore b/frameworks/remix/.gitignore index 80ec311..7c02801 100644 --- a/frameworks/remix/.gitignore +++ b/frameworks/remix/.gitignore @@ -3,3 +3,4 @@ node_modules /.cache /build .env +.vercel diff --git a/frameworks/remix/app/routes/_index.tsx b/frameworks/remix/app/routes/_index.tsx index e9e2d35..8f8c275 100644 --- a/frameworks/remix/app/routes/_index.tsx +++ b/frameworks/remix/app/routes/_index.tsx @@ -5,15 +5,12 @@ import { LoaderFunctionArgs, json } from "@remix-run/node"; import { Icon } from "@iconify/react"; export async function loader({ request }: LoaderFunctionArgs) { - console.log("🚀 ~ loader ~ request:", authenticator); - const user = await authenticator.isAuthenticated(request); return json(user); } export default function Index() { const authenticatedUser = useLoaderData(); - console.log("🚀 ~ Index ~ authenticatedUser:", authenticatedUser); return (
From 72077fddb9cd9ff972a0740ab1aaa79cef0fdf1c Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Thu, 25 Jul 2024 16:16:13 -0600 Subject: [PATCH 07/25] adjust typo --- .github/workflows/nextjs.yml | 2 +- .github/workflows/react.yml | 2 +- .github/workflows/remix.yml | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nextjs.yml b/.github/workflows/nextjs.yml index 9b509bd..e7f1be6 100644 --- a/.github/workflows/nextjs.yml +++ b/.github/workflows/nextjs.yml @@ -1,4 +1,4 @@ -name: Deploy Next.js Example to Vercel +name: Deploy Next.js Example env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} diff --git a/.github/workflows/react.yml b/.github/workflows/react.yml index 47086ff..fed262e 100644 --- a/.github/workflows/react.yml +++ b/.github/workflows/react.yml @@ -1,4 +1,4 @@ -name: Deploy React Example to Vercel +name: Deploy React Example env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} diff --git a/.github/workflows/remix.yml b/.github/workflows/remix.yml index 0e8d3ef..01aa441 100644 --- a/.github/workflows/remix.yml +++ b/.github/workflows/remix.yml @@ -1,5 +1,4 @@ -name: Deploy React Example to Vercel - +name: Deploy Remix Example env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_REMIX_PROJECT_ID }} From d930a603d6508255659296fa85911f6b890eebb3 Mon Sep 17 00:00:00 2001 From: pnzrp2 Date: Fri, 26 Jul 2024 11:40:53 -0600 Subject: [PATCH 08/25] change .pngs to .webp, remove unused logo images --- frameworks/nextjs/public/logo192.png | Bin 3248 -> 0 bytes frameworks/nextjs/public/logo512.png | Bin 8140 -> 0 bytes frameworks/nuxt/keycloak-js/app.vue | 6 +++--- .../nuxt/keycloak-js/components/Header.vue | 6 +++--- .../nuxt/keycloak-js/public/home-bg-mobile.jpg | Bin 440238 -> 0 bytes .../keycloak-js/public/home-bg-mobile.webp | Bin 0 -> 7632 bytes frameworks/nuxt/keycloak-js/public/home-bg.jpg | Bin 415879 -> 0 bytes .../nuxt/keycloak-js/public/home-bg.webp | Bin 0 -> 8428 bytes frameworks/nuxt/keycloak-js/public/logo192.png | Bin 3248 -> 0 bytes frameworks/nuxt/keycloak-js/public/logo512.png | Bin 8140 -> 0 bytes .../nuxt/oidc-client-ts/components/Header.vue | 6 +++--- .../oidc-client-ts/public/home-bg-mobile.jpg | Bin 440238 -> 0 bytes .../oidc-client-ts/public/home-bg-mobile.webp | Bin 0 -> 7632 bytes .../nuxt/oidc-client-ts/public/home-bg.jpg | Bin 415879 -> 0 bytes .../nuxt/oidc-client-ts/public/home-bg.webp | Bin 0 -> 8428 bytes .../nuxt/oidc-client-ts/public/logo192.png | Bin 3248 -> 0 bytes .../nuxt/oidc-client-ts/public/logo512.png | Bin 8140 -> 0 bytes frameworks/reactjs/public/home-bg-mobile.jpg | Bin 440238 -> 0 bytes frameworks/reactjs/public/home-bg-mobile.webp | Bin 0 -> 7632 bytes frameworks/reactjs/public/home-bg.jpg | Bin 415879 -> 0 bytes frameworks/reactjs/public/home-bg.webp | Bin 0 -> 8428 bytes frameworks/reactjs/src/App.tsx | 6 +++--- frameworks/remix/app/routes/_index.tsx | 6 +++--- frameworks/remix/public/home-bg-mobile.jpg | Bin 440238 -> 0 bytes frameworks/remix/public/home-bg-mobile.webp | Bin 0 -> 7632 bytes frameworks/remix/public/home-bg.jpg | Bin 415879 -> 0 bytes frameworks/remix/public/home-bg.webp | Bin 0 -> 8428 bytes frameworks/remix/public/logo192.png | Bin 3248 -> 0 bytes frameworks/remix/public/logo512.png | Bin 8140 -> 0 bytes .../app/components/home/home.component.html | 6 +++--- .../src/assets/home-bg-mobile.jpg | Bin 440238 -> 0 bytes .../src/assets/home-bg-mobile.webp | Bin 0 -> 7632 bytes .../angularclient/src/assets/home-bg.jpg | Bin 415879 -> 0 bytes .../angularclient/src/assets/home-bg.webp | Bin 0 -> 8428 bytes .../angularclient/src/assets/logo192.png | Bin 3248 -> 0 bytes .../angularclient/src/assets/logo512.png | Bin 8140 -> 0 bytes frameworks/sveltekit/src/routes/+page.svelte | 6 +++--- frameworks/sveltekit/static/home-bg-mobile.jpg | Bin 440238 -> 0 bytes .../sveltekit/static/home-bg-mobile.webp | Bin 0 -> 7632 bytes frameworks/sveltekit/static/home-bg.jpg | Bin 415879 -> 0 bytes frameworks/sveltekit/static/home-bg.webp | Bin 0 -> 8428 bytes frameworks/sveltekit/static/logo192.png | Bin 3248 -> 0 bytes frameworks/sveltekit/static/logo512.png | Bin 8140 -> 0 bytes frameworks/vue/public/home-bg-mobile.jpg | Bin 440238 -> 0 bytes frameworks/vue/public/home-bg-mobile.webp | Bin 0 -> 7632 bytes frameworks/vue/public/home-bg.jpg | Bin 415879 -> 0 bytes frameworks/vue/public/home-bg.webp | Bin 0 -> 8428 bytes frameworks/vue/public/logo192.png | Bin 3248 -> 0 bytes frameworks/vue/public/logo512.png | Bin 8140 -> 0 bytes 49 files changed, 21 insertions(+), 21 deletions(-) delete mode 100644 frameworks/nextjs/public/logo192.png delete mode 100644 frameworks/nextjs/public/logo512.png delete mode 100644 frameworks/nuxt/keycloak-js/public/home-bg-mobile.jpg create mode 100644 frameworks/nuxt/keycloak-js/public/home-bg-mobile.webp delete mode 100644 frameworks/nuxt/keycloak-js/public/home-bg.jpg create mode 100644 frameworks/nuxt/keycloak-js/public/home-bg.webp delete mode 100644 frameworks/nuxt/keycloak-js/public/logo192.png delete mode 100644 frameworks/nuxt/keycloak-js/public/logo512.png delete mode 100644 frameworks/nuxt/oidc-client-ts/public/home-bg-mobile.jpg create mode 100644 frameworks/nuxt/oidc-client-ts/public/home-bg-mobile.webp delete mode 100644 frameworks/nuxt/oidc-client-ts/public/home-bg.jpg create mode 100644 frameworks/nuxt/oidc-client-ts/public/home-bg.webp delete mode 100644 frameworks/nuxt/oidc-client-ts/public/logo192.png delete mode 100644 frameworks/nuxt/oidc-client-ts/public/logo512.png delete mode 100644 frameworks/reactjs/public/home-bg-mobile.jpg create mode 100644 frameworks/reactjs/public/home-bg-mobile.webp delete mode 100644 frameworks/reactjs/public/home-bg.jpg create mode 100644 frameworks/reactjs/public/home-bg.webp delete mode 100644 frameworks/remix/public/home-bg-mobile.jpg create mode 100644 frameworks/remix/public/home-bg-mobile.webp delete mode 100644 frameworks/remix/public/home-bg.jpg create mode 100644 frameworks/remix/public/home-bg.webp delete mode 100644 frameworks/remix/public/logo192.png delete mode 100644 frameworks/remix/public/logo512.png delete mode 100644 frameworks/spring-boot-keycloak/angularclient/src/assets/home-bg-mobile.jpg create mode 100644 frameworks/spring-boot-keycloak/angularclient/src/assets/home-bg-mobile.webp delete mode 100644 frameworks/spring-boot-keycloak/angularclient/src/assets/home-bg.jpg create mode 100644 frameworks/spring-boot-keycloak/angularclient/src/assets/home-bg.webp delete mode 100644 frameworks/spring-boot-keycloak/angularclient/src/assets/logo192.png delete mode 100644 frameworks/spring-boot-keycloak/angularclient/src/assets/logo512.png delete mode 100644 frameworks/sveltekit/static/home-bg-mobile.jpg create mode 100644 frameworks/sveltekit/static/home-bg-mobile.webp delete mode 100644 frameworks/sveltekit/static/home-bg.jpg create mode 100644 frameworks/sveltekit/static/home-bg.webp delete mode 100644 frameworks/sveltekit/static/logo192.png delete mode 100644 frameworks/sveltekit/static/logo512.png delete mode 100644 frameworks/vue/public/home-bg-mobile.jpg create mode 100644 frameworks/vue/public/home-bg-mobile.webp delete mode 100644 frameworks/vue/public/home-bg.jpg create mode 100644 frameworks/vue/public/home-bg.webp delete mode 100644 frameworks/vue/public/logo192.png delete mode 100644 frameworks/vue/public/logo512.png diff --git a/frameworks/nextjs/public/logo192.png b/frameworks/nextjs/public/logo192.png deleted file mode 100644 index 8833ec9ea6505821bdca6ad094ff3b8dc18057a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3248 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 diff --git a/frameworks/nuxt/keycloak-js/app.vue b/frameworks/nuxt/keycloak-js/app.vue index b6f07fa..0315d44 100644 --- a/frameworks/nuxt/keycloak-js/app.vue +++ b/frameworks/nuxt/keycloak-js/app.vue @@ -1,11 +1,11 @@