Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(adapter-nextjs): server-side auth flows integrating cognito hosted UI #13827

Open
wants to merge 4 commits into
base: feat/server-auth/main
Choose a base branch
from

Conversation

HuiSF
Copy link
Member

@HuiSF HuiSF commented Sep 19, 2024

Description of changes

Implemented the following flow integrating Cognito Hosted UI endpoints:

  1. sign-in -> Hosted UI -> sign-in-callback (including Social Providers) -> httpOnly cookies
  2. sign-up -> Hosted UI -> sign-in-callback -> httpOnly cookies
  3. sign-out -> Hosted UI -> sign-out-callback -> httpOnly cookies

API Route handlers work with both Next.js App Router and Pages Router.

Issue #, if available

Description of how you validated changes

  1. Unit tests
  2. Manual testing with Next.js samples apps created with the App Router and Pages Router

Checklist

  • PR description included
  • yarn test passes
  • Unit Tests are changed or added
  • Relevant documentation is changed or added (and PR referenced)

Checklist for repo maintainers

  • Verify E2E tests for existing workflows are working as expected or add E2E tests for newly added workflows
  • New source file paths included in this PR have been added to CODEOWNERS, if appropriate

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
…ide auth…ide auth…ide auth

"alwaysStrict": true
"alwaysStrict": true,
"lib": [
"esnext"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The base tsconfig has jsdom as a lib, that makes origin variable a legit global variable which is not desired.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing impl. moved out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing impl. moved out.

@ashika112 ashika112 changed the title eat(adapter-nextjs): server-side auth flows integrating cognio hosted UI feat(adapter-nextjs): server-side auth flows integrating cognio hosted UI Sep 19, 2024
@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch from 6087817 to ae36b32 Compare September 19, 2024 17:23
Comment on lines +61 to +63
path: '/',
httpOnly: true,
secure: true,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three attributes are not configurable.

@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch from ae36b32 to 621d0cb Compare September 19, 2024 18:26
@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/2-auth-api-handlers branch from 25c4eaa to 26ec9ed Compare October 1, 2024 23:02
@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch from 621d0cb to 284acbf Compare October 1, 2024 23:02
@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/2-auth-api-handlers branch from 26ec9ed to 67d073f Compare November 21, 2024 17:05
@HuiSF HuiSF requested a review from pranavosu as a code owner November 21, 2024 17:05
@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch from 284acbf to 0ef2b81 Compare November 21, 2024 17:06
@jjarvisp jjarvisp changed the title feat(adapter-nextjs): server-side auth flows integrating cognio hosted UI feat(adapter-nextjs): server-side auth flows integrating cognito hosted UI Nov 22, 2024
Copy link
Member

@jjarvisp jjarvisp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost done with review, I should be able to wrap up soon.

const decoded = decodeJWT(accessToken);
const issuedAt = (decoded.payload.iat ?? 0) * 1000;
const clockDrift = issuedAt > 0 ? issuedAt - Date.now() : 0;
const username = (decoded.payload.username as string) ?? 'username';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there valid scenarios when username would be missing from payload or any particular reasoning around default username to "username"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. I just followed the original client-side impl.
This is a good question, let me dig and get back to you.

Base automatically changed from hui/feat/adapter-nextjs/2-auth-api-handlers to feat/server-auth/main December 20, 2024 18:56
@HuiSF HuiSF requested a review from sktimalsina as a code owner December 20, 2024 18:56
@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch from 0ef2b81 to ff48e7a Compare December 21, 2024 00:30
}) => {
const { code, state } = resolveCodeAndStateFromUrl(request.url);
if (!code || !state) {
return new Response(null, { status: 400 });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we see needs for customers to customize the error payloads and render different messages accordingly?

);
appendSetCookieHeaders(
headers,
createSignInFlowProofCookies({ state: '', pkce: '' }),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nit: prefer to re-name this locally to callout the cookie removal, similar to the next line. Something like

		createSignInFlowProofRemoveCookies(),

Which is also a similar practice to the createTokenRemoveCookies below

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function sets only cookie name-value - which is not add or remove specific. The only difference is on the options.

oAuthConfig,
setCookieOptions,
}) => {
const { [IS_SIGNING_OUT_COOKIE_NAME]: isSigningOut } =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarification question, how is this isSigningOut cookie used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When isSigningOut is true proceed with handleSignOutCallback otherwise client is doing something wrong.

setCookieOptions,
type,
}) => {
const { codeVerifier, state } = createAuthFlowProofs({ customState });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify question: do we need to return early if CX is already signed in?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's what's the next PR adds: #13839

httpOnly: true,
secure: true,
sameSite: 'lax' as const,
expires: new Date(Date.now() + AUTH_FLOW_PROOF_COOKIE_EXPIRY),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to count for clock drift here? Maybe it's handled in the orchestrator, but just want to double check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question - should use maxAge attribute here to avoid concerns of clock drift. Will update.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do this in a separate PR.

oAuthConfig: OAuthConfig,
) => {
const redirectUrl = oAuthConfig.redirectSignIn.find(url =>
url.startsWith(origin),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use the URL util and parse the origin from the oAuthConfig more strictly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's necessary to construct a URL object from the config redirect URL strings - as a client-side validation this should be good enough, as eventually HostedUI will also match the URL on the service side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants