Skip to content

Commit

Permalink
add basic configuration for auth and NHS login
Browse files Browse the repository at this point in the history
  • Loading branch information
chrimesdev committed Jan 15, 2025
1 parent 7c8f8e1 commit ea90ffe
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 5 deletions.
9 changes: 8 additions & 1 deletion web/.env.development.sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# Default
NEXT_PUBLIC_BASE_URL=http://localhost:3000
NODE_ENV=development
SERVICE_NAME="Participant Manager"
SERVICE_NAME=Participant Manager

# Auth
NEXTAUTH_URL=https://localhost:3000/api/auth
NEXTAUTH_SECRET=
AUTH_NHSLOGIN_ISSUER_URL=https://auth.sandpit.signin.nhs.uk
AUTH_NHSLOGIN_CLIENT_ID=""
AUTH_NHSLOGIN_CLIENT_SECRET=""
9 changes: 9 additions & 0 deletions web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,17 @@ Create a `.env` file which should override environment variables required to run
NEXT_PUBLIC_BASE_URL=http://localhost:3000
NODE_ENV=development
SERVICE_NAME="UI template"

# Auth
NEXTAUTH_URL=https://localhost:3000/api/auth
NEXTAUTH_SECRET={RANDOM_SECRET_STRING}
AUTH_NHSLOGIN_ISSUER_URL=https://auth.sandpit.signin.nhs.uk
AUTH_NHSLOGIN_CLIENT_ID={CLIENT_ID}
AUTH_NHSLOGIN_CLIENT_SECRET={CLIENT_SECRET}
```

For `NEXTAUTH_SECRET` you can use `openssl rand -base64 32` or [https://generate-secret.vercel.app/32](https://generate-secret.vercel.app/32) to generate a random value.

## Testing

### Unit tests
Expand Down
5 changes: 5 additions & 0 deletions web/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { handlers } from "@/app/lib/auth";

export const { GET, POST } = handlers;

export { auth as middleware } from "@/app/lib/auth";
37 changes: 37 additions & 0 deletions web/app/components/signInButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { signIn } from "@/app/lib/auth";
import styles from "@/app/styles/components/signIn.module.scss";

export default function SignInButton() {
return (
<form
action={async () => {
"use server";
await signIn("nhs-login");
}}
>
<button
className={`nhsuk-button app-button--login ${styles["app-button--login"]} nhsuk-u-margin-bottom-4`}
data-module="nhsuk-button"
type="submit"
>
<svg
className="nhsuk-logo"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 80 32"
height="27"
aria-hidden="true"
focusable="false"
>
<path
fill="currentColor"
d="M80 0v32H0V0h80ZM69 2.2c-5.8 0-11.6 2-11.6 8.8 0 7.4 10.2 5.8 10.2 10 0 2.6-3.4 3-5.6 3-2.2 0-5-.6-6.4-1.4L54 28c2.2.8 5.4 1.4 8 1.4 6.2 0 12.8-1.8 12.8-9 0-7.8-10.2-6.6-10.2-10.2 0-2.2 2.2-2.6 5-2.6 2.6 0 4.4.6 5.8 1.2L77 3.4c-1.8-.8-4.8-1.2-8-1.2ZM16.6 3H7.8L2.2 29h6.6l3.6-18h.2L18 29h8.6l5.6-26h-6.6L22 21h-.2L16.6 3Zm25.2 0h-7.2l-5.2 26h6.8l2.4-11.2h8.2L44.6 29h7L57 3h-7l-2.2 9.8h-8l2-9.8Z"
></path>
</svg>

<div>
<span>Continue with</span> NHS login
</div>
</button>
</form>
);
}
26 changes: 26 additions & 0 deletions web/app/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import NextAuth, { Profile } from "next-auth";
import { OAuthConfig } from "next-auth/providers";

const NHS_CIS2: OAuthConfig<Profile> = {
id: "nhs-login",
name: "NHS login authentication",
type: "oidc",
issuer: `${process.env.AUTH_NHSLOGIN_ISSUER_URL}`,
wellKnown: `${process.env.AUTH_NHSLOGIN_ISSUER_URL}/.well-known/openid-configuration`,
clientId: process.env.AUTH_NHSLOGIN_CLIENT_ID,
clientSecret: process.env.AUTH_NHSLOGIN_CLIENT_SECRET,
authorization: {
params: {
scope: "",
},
},
client: {
token_endpoint_auth_method: "client_secret_post",
},
idToken: false,
checks: ["state"],
};

export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [NHS_CIS2],
});
12 changes: 9 additions & 3 deletions web/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import type { Metadata } from "next";
import { auth } from "@/app/lib/auth";
import SignInButton from "@/app/components/signInButton";

export const metadata: Metadata = {
title: `Hello world - ${process.env.SERVICE_NAME}`,
title: `Overview - ${process.env.SERVICE_NAME}`,
};

export default function Home() {
export default async function Home() {
const session = await auth();

return (
<main className="nhsuk-main-wrapper" id="maincontent" role="main">
<h1>Hello world</h1>
<h1>Overview</h1>
{!session?.user && <SignInButton />}
{session?.user && <p>Welcome, {session.user.name}! You are signed in.</p>}
</main>
);
}
127 changes: 127 additions & 0 deletions web/app/styles/components/signIn.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
@import "~nhsuk-frontend/packages/core/tools/_typography.scss";
@import "~nhsuk-frontend/packages/core/tools/_sass-mq.scss";
@import "~nhsuk-frontend/packages/core/tools/_mixins.scss";
@import "~nhsuk-frontend/packages/core/settings/_colours.scss";
@import "~nhsuk-frontend/packages/core/settings/_globals.scss";
@import "~nhsuk-frontend/packages/core/settings/_typography.scss";
@import "~nhsuk-frontend/packages/core/utilities/_visually-hidden.scss";

$app-login-button-color: $color_nhsuk-blue;
$app-login-button-hover-color: mix($app-login-button-color, #003087, 50%);
$app-login-button-active-color: #003087;
$app-login-button-shadow-color: #003087;
$button-shadow-size: 4px;

.app-button--login {
align-items: center;
background-color: $app-login-button-color;
box-shadow: 0 $button-shadow-size 0 $app-login-button-shadow-color;
display: inline-flex;
gap: 16px;

&span {
@include mq($until: desktop) {
@include visually-hidden();
}
}

&:hover {
background-color: $app-login-button-hover-color;
}

&:focus {
background: $nhsuk-focus-color;
box-shadow: 0 $button-shadow-size 0 $nhsuk-focus-text-color;
color: $nhsuk-focus-text-color;
outline: $nhsuk-focus-width solid transparent;
}

&:active {
background: $app-login-button-active-color;
box-shadow: none;
color: $nhsuk-button-text-color;
top: $button-shadow-size;
}
}

// Proposed secondary button style
// See https://github.com/nhsuk/nhsapp-frontend/issues/12
// See https://github.com/nhsuk/nhs-app-design-styles-components-patterns
@mixin app-button-secondary($button-color) {
background-color: transparent;
border-bottom: 0;
border-color: $button-color;
box-shadow: 0 4px 0 $button-color;
color: $button-color;
// Adjust padding to account for removal of 2px bottom border
padding-bottom: 13px;
padding-top: 13px;

&:link,
&:visited {
color: $button-color;
}

&:hover {
background-color: rgba($button-color, 10%);
color: $button-color;
}

&:focus {
background-color: $nhsuk-focus-color;
border-color: $nhsuk-focus-color;
color: $nhsuk-focus-text-color;
}

&:focus:visited:active {
// Override .nhsuk-button turning colour white
color: $button-color;
}

&:active {
background-color: rgba($button-color, 15%);
border-bottom: $nhsuk-border-width-form-element solid; // Reintroduce 2px bottom border
border-color: $button-color;
color: $button-color;
// Revert padding to account for reintroduction of 2px bottom border
padding-bottom: 12px;
padding-top: 12px;
}

&::before {
bottom: #{$button-shadow-size * -1};
top: #{$nhsuk-border-width-form-element * -1};
}

&:active::before {
bottom: #{($nhsuk-border-width-form-element + $button-shadow-size) * -1};
top: #{($nhsuk-border-width-form-element + $button-shadow-size) * -1};
}
}

.app-button--secondary {
@include app-button-secondary($nhsuk-link-color);
}

.app-button--secondary-warning {
@include app-button-secondary($nhsuk-warning-button-color);
}

.app-button--small {
@include nhsuk-typography-responsive(16);
padding: nhsuk-spacing(1) 12px;

&.app-button--secondary,
&.app-button--secondary-warning {
// Adjust padding to account for removal of 2px bottom border
padding-bottom: #{nhsuk-spacing(1) + 1px};
padding-top: #{nhsuk-spacing(1) + 1px};

&:active {
margin-bottom: -1px;
// Revert padding to account for reintroduction of 2px bottom border
padding-bottom: nhsuk-spacing(1);
padding-top: nhsuk-spacing(1);
}
}
}
Empty file removed web/app/styles/main.scss
Empty file.
2 changes: 1 addition & 1 deletion web/e2e/example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { test, expect } from "@playwright/test";

test("navigate to the Index page", async ({ page }) => {
await page.goto("http://localhost:3000/");
await expect(page).toHaveTitle(/Hello world/);
await expect(page).toHaveTitle(/Overview/);
});

0 comments on commit ea90ffe

Please sign in to comment.