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

Merged

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.

"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.

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 username in the token payload corresponds the username in a Cognito user pool, and the username of a user in a Cognito user pool is always defined. From this I think we can safely remove the redundant default value fallback.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed, thanks for looking into this.

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?

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 - This particular spot is for unwrapping code and state to defined strings, and here it's redirecting back from Hosted UI endpoint, they should always be provided.

Though in the current implementation we are returning 400 response when state and pkce cookies are not presented (expired in 10 minutes without the end user completing the sign in) I will keep the implementation as is and looking into how to surface an error for this situation.

);
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: 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.

Copy link
Member

Choose a reason for hiding this comment

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

Is startsWith sufficient to handle different domains but with the same subdomains, e.g. sub.abc.io v.s. sub.abc.io.com?

Copy link
Member Author

Choose a reason for hiding this comment

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

Well the origin remain unchanged (configured once by env var) as the predicate to look up a corresponding url from redirectURLs, and we are match origin starting from the protocol rather than a domain, I still think it's sufficient.

@HuiSF HuiSF force-pushed the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch from a585318 to 56dd741 Compare January 2, 2025 21:33
@HuiSF HuiSF merged commit 1162419 into feat/server-auth/main Jan 2, 2025
28 checks passed
HuiSF added a commit that referenced this pull request Jan 2, 2025
…ed UI (#13827)

* chore(auth): export necessary utilities and types to support server-side auth

* chore(aws-amplify): export necessary utilities to support server-side auth

* feat(adapter-nextjs): server-side auth api route integrating cognito hosted ui

* chore(adapter-nextjs): resolve comments

* refactor(adapter-nextjs): remove redundant username fallback
@HuiSF HuiSF deleted the hui/feat/adapter-nextjs/3-auth-api-handlers-impl branch January 2, 2025 21:48
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