Skip to content

Commit

Permalink
110 fix server side authentification (#133)
Browse files Browse the repository at this point in the history
Co-authored-by: Sigrid Elnan <[email protected]>
  • Loading branch information
jonasbjoralt and sigridge authored Oct 13, 2023
1 parent f15390a commit ffab112
Show file tree
Hide file tree
Showing 24 changed files with 304 additions and 531 deletions.
121 changes: 47 additions & 74 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,80 +14,6 @@ on:
workflow_dispatch:

jobs:
build-and-deploy-frontend:
name: 'Build and deploy Frontend'
runs-on: ubuntu-latest
environment: Development

defaults:
run:
working-directory: frontend

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Node.js version
uses: actions/setup-node@v3
with:
node-version: "18.x"

- name: Restore cache
uses: actions/cache@v3
with:
path: |
frontend/.next/cache
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-
- name: Install ci dependencies
run: yarn --frozen-lockfile --ignore-scripts

- name: Build with Next.js (NO)
run: |
yarn build
mv ./build/static ./build/standalone/build
cp -r ./public ./build/standalone/
mv ./build ./build-no
env:
NEXT_PUBLIC_VIBES_BACKEND_URL: ${{ vars.NEXT_PUBLIC_VIBES_BACKEND_URL_NO }}
NEXT_PUBLIC_CLIENT_ID: ${{ vars.NEXT_PUBLIC_CLIENT_ID }}
NEXT_PUBLIC_TENANT_ID: ${{ vars.NEXT_PUBLIC_TENANT_ID }}
NEXT_PUBLIC_APP_SCOPE: ${{ vars.NEXT_PUBLIC_APP_SCOPE }}

- name: Build with Next.js (SE)
run: |
yarn build
mv ./build/static ./build/standalone/build
cp -r ./public ./build/standalone
mv ./build ./build-se
env:
NEXT_PUBLIC_VIBES_BACKEND_URL: ${{ vars.NEXT_PUBLIC_VIBES_BACKEND_URL_SE }}
NEXT_PUBLIC_CLIENT_ID: ${{ vars.NEXT_PUBLIC_CLIENT_ID }}
NEXT_PUBLIC_TENANT_ID: ${{ vars.NEXT_PUBLIC_TENANT_ID }}
NEXT_PUBLIC_APP_SCOPE: ${{ vars.NEXT_PUBLIC_APP_SCOPE }}


- name: Deploy to App Service (NO)
id: deploy-to-webapp-no
uses: azure/webapps-deploy@v2
with:
app-name: 'vibes-frontend-norway-dev'
slot-name: 'Production'
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_FRONTEND_NO }}
package: ./frontend/build-no/standalone

- name: Deploy to App Service (SE)
id: deploy-to-webapp-se
uses: azure/webapps-deploy@v2
with:
app-name: 'vibes-frontend-sweden-dev'
slot-name: 'Production'
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_FRONTEND_SE }}
package: ./frontend/build-se/standalone

build-and-deploy-backend:
name: 'Build and deploy Backend'
Expand Down Expand Up @@ -127,3 +53,50 @@ jobs:
app-name: vibes-backend-sweden-dev
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_BACKEND_SE }} # Define secret variable in repository settings as per action documentation
package: 'backend/Api/build'

build-frontend:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0

- name: Log in to GitHub container registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}

- name: Lowercase the repo name and username
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}

- name: Build and push container image to registry
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
with:
push: true
tags: ghcr.io/${{ env.REPO }}-frontend:${{ github.sha }}
file: Frontend.Dockerfile

deploy-frontend:
permissions:
contents: none
runs-on: ubuntu-latest
needs: build-frontend
environment:
name: 'Development'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

steps:
- name: Lowercase the repo name and username
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}

- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: vibes-frontend-dev
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_FRONTEND }}
images: 'ghcr.io/${{ env.REPO }}-frontend:${{ github.sha }}'
28 changes: 3 additions & 25 deletions frontend/Dockerfile → Frontend.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
FROM base AS builder
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY yarn.lock* package.json ./
COPY ./frontend .
RUN yarn --frozen-lockfile --ignore-scripts;


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /bundle
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN yarn build

# If using npm comment out above and use below instead
# RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
Expand All @@ -32,18 +19,9 @@ ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /bundle/public ./public

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /bundle/build/standalone ./
COPY --from=builder --chown=nextjs:nodejs /bundle/build/static ./build/static

USER nextjs

EXPOSE 3000
Expand All @@ -52,4 +30,4 @@ ENV PORT 3000
# set hostname to localhost
ENV HOSTNAME "0.0.0.0"

CMD ["node", "server.js"]
CMD ["yarn", "start"]
5 changes: 3 additions & 2 deletions backend/Api/Consultants/ConsultantController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public ConsultantController(ApplicationContext context, IMemoryCache cache, Cons
[HttpGet]
public ActionResult<List<ConsultantReadModel>> Get(
[FromQuery(Name = "weeks")] int numberOfWeeks = 8,
[FromQuery(Name = "includeOccupied")] bool includeOccupied = false)
[FromQuery(Name = "includeOccupied")] bool includeOccupied = true)
{
var consultants = GetConsultantsWithAvailability(numberOfWeeks)
.Where(c =>
Expand Down Expand Up @@ -88,7 +88,8 @@ private List<Consultant> LoadConsultantAvailability(int numberOfWeeks)
{
var applicableWeeks = DateService.GetNextWeeks(numberOfWeeks);
var firstDayOfCurrentWeek = DateService.GetFirstDayOfWeekContainingDate(DateTime.Now);
var firstWorkDayOutOfScope = DateService.GetFirstDayOfWeekContainingDate(DateTime.Now.AddDays(numberOfWeeks*7));
var firstWorkDayOutOfScope =
DateService.GetFirstDayOfWeekContainingDate(DateTime.Now.AddDays(numberOfWeeks * 7));

// Needed to filter planned absence and staffing.
// From november, we will span two years.
Expand Down
2 changes: 1 addition & 1 deletion backend/Api/Departments/DeparmentController.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Database.DatabaseContext;
using Microsoft.AspNetCore.Mvc;

[Route("/departments")]
[Route("/v0/departments")]
[ApiController]
public class DepartmentController : ControllerBase {

Expand Down
11 changes: 6 additions & 5 deletions frontend/.env.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
NEXT_PUBLIC_CLIENT_ID=<client-id> # App Registrations (Azure portal) -> select app reg -> Copy client ID
NEXT_PUBLIC_TENANT_ID=<tenant-id> # App Registrations (Azure portal) -> select app reg -> Copy tenant ID
NEXT_PUBLIC_APP_SCOPE= # App Registrations (Azure portal) -> select app reg -> Expose an API -> Copy scope ID (i.e. api://oidajwoig/...)

# NEXT_PUBLIC_VIBES_BACKEND_URL= #Not necessary for local development, defaults to localhost api
AZURE_AD_CLIENT_ID= # App Registrations (Azure portal) -> select app reg -> Copy client ID
AZURE_AD_TENANT_ID= # App Registrations (Azure portal) -> select app reg -> Copy tenant ID
AZURE_AD_APP_SCOPE= # App Registrations (Azure portal) -> select app reg -> Expose an API -> Copy scope ID (i.e. api://oidajwoig/...)
AZURE_AD_CLIENT_SECRET= #Generate from app registration
NEXTAUTH_SECRET= # High-entroy random secret
NEXTAUTH_URL= # i.e. http://localhost:3000
13 changes: 1 addition & 12 deletions frontend/next.config.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
/** @type {import('next').NextConfig} */

const apiBackendUrl =
process.env.NEXT_PUBLIC_VIBES_BACKEND_URL ?? "http://localhost:7172"; // See backend/launchSettings.json for details on dev-env
// See backend/launchSettings.json for details on dev-env

const nextConfig = {
async rewrites() {
return [
{
source: "/api/:path*",
destination: `${apiBackendUrl}/:path*`,
},
];
},
output: "standalone",
distDir: "build",
swcMinify: true,
modularizeImports: {
Expand Down
5 changes: 2 additions & 3 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
"private": true,
"scripts": {
"dev": "next dev",
"start-test": "NEXT_PUBLIC_NO_AUTH=true next dev",
"start-test": "NEXT_PUBLIC_NO_AUTH=true NEXTAUTH_SECRET='insecure-secret' next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prettier:ci": "prettier --check . "
},
"dependencies": {
"@azure/msal-browser": "^3.1.0",
"@azure/msal-react": "^2.0.3",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.9",
Expand All @@ -24,6 +22,7 @@
"eslint": "8.48.0",
"eslint-config-next": "^13.5.2",
"next": "^13.5.2",
"next-auth": "^4.23.2",
"postcss": "^8.4.31",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
54 changes: 54 additions & 0 deletions frontend/src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { AuthOptions, getServerSession, Session } from "next-auth";
import AzureADProvider from "next-auth/providers/azure-ad";

export type CustomSession = {
id_token?: string;
access_token?: string;
} & Session;

export const authOptions: AuthOptions = {
// Configure one or more authentication providers
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID!,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET!,
tenantId: process.env.AZURE_AD_TENANT_ID!,
authorization: {
params: {
scope: `openid profile email ${process.env.AZURE_AD_APP_SCOPE}`,
},
},
idToken: true,
}),
],
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
},

callbacks: {
async redirect({ baseUrl }) {
return baseUrl;
},
async jwt({ token, account }) {
if (account) {
token.id_token = account.id_token;
token.access_token = account.access_token;
}
return token;
},
async session({ session, token }) {
if (session) {
session = Object.assign({}, session, {
id_token: token.id_token,
access_token: token.access_token,
});
}
return session;
},
},
};

export async function getCustomServerSession(authOptions: AuthOptions) {
return (await getServerSession(authOptions)) as CustomSession;
}
32 changes: 12 additions & 20 deletions frontend/src/app/bemanning/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
"use client";

import FilteredConsultantsList from "@/components/FilteredConsultantsList";
import useVibesApi from "@/hooks/useVibesApi";
import { CircularProgress } from "@mui/material";

export default function Bemanning() {
const { data, isLoading } = useVibesApi(true);

if (isLoading) {
return <CircularProgress />;
}

if (data) {
return (
<div>
<h1>Konsulenter</h1>
<FilteredConsultantsList consultants={data} />
</div>
);
}
import { fetchWithToken } from "@/data/fetchWithToken";
import { Variant } from "@/types";

export default async function Bemanning() {
const consultants = (await fetchWithToken<Variant[]>("variants")) ?? [];

return (
<div>
<h1>Konsulenter</h1>
<FilteredConsultantsList consultants={consultants} />
</div>
);
}
Loading

0 comments on commit ffab112

Please sign in to comment.