-
Notifications
You must be signed in to change notification settings - Fork 298
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
Refactor clerk/backend #2389
Refactor clerk/backend #2389
Conversation
🦋 Changeset detectedLatest commit: 99906da The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
||
class ClerkRequest extends Request { | ||
clerkUrl: URL; | ||
cookies: Map<string, string>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ could we make the clerkUrl
and cookies
read-only to avoid accidentally replacing them or expecting that updating them would affect our result.
I think that both ClerkRequest
and AuthenticateContext
should be read-only objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done :)
test('is not CO with IPv6', assert => { | ||
const originURL = new URL('http://[::1]'); | ||
const host = new URL('http://[::1]').host; | ||
assert.false(checkCrossOrigin({ originURL, host })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ @SokratisVidros did we remove the checkCrossOrigin
(which was part of the interstitial) in the handshake?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, I've found no references in the codebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔧 I would suggest we keep types close to their usage and use types.ts
for generic types related to specific package. Eg move RequestStateParams
to tokens/authStatus.ts
or tokens/request.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to extract these to a new file to avoid circular dependencies between authStatus
<> request
, but let me take another look and see if I can avoid this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
☝️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need these for authenticateRequest and AuthenticateContext right now. Since we will continue refactoring the types and structs in clerk/backend after v5 as part of flex work, shall we fix this then?
@@ -0,0 +1,88 @@ | |||
import { constants } from '../constants'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These classes will be moved to a different dir when I wrap up my work on clerkMiddleware
* is in a signed in or signed out state or if we need | ||
* to perform a handshake. | ||
*/ | ||
class AuthenticateContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This naming feels weird as it looks like a React Context. Do we even need a class at this point? This is a very nit-picky comment, so you can ignore it for now, but I wanted to raise the point that the abstraction might not help as much as intended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikosdouvlis Will we just pass a Request object afterall?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW this is a great candidate for async local storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... that the abstraction might not help as much as intended.
BTW this is a great candidate for async local storage.
Let me reply to these two together, as my intention is for us to use AuthenticateContext
or a similar struct with Async Local Storage, but only after we simplify type-handling in clerk/backend and we decide that the abstraction works for us
I will not refactor anything else to use AuthenticateContext
as I've simplified the problematic types for now. Let's do a design session and talk more about it
import { constants } from '../constants'; | ||
|
||
export type WithClerkUrl<T> = T & { | ||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Do we still need this in the handshake world?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still need it for authenticateRequest
and redirectToSignIn
/protect
from within clerkMiddleware
and authMiddleware
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice cleanup
export const createClerkRequest = (...args: ConstructorParameters<typeof ClerkRequest>): ClerkRequest => { | ||
return new ClerkRequest(...args); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ What's the benefit of using a factory function here? If it's a straight pass-through to the constructor it feels unecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a pattern I like but don't have strong opinions about. It's a way to export a class as type only while providing a factory so consumers can use ClerkRequest
as a type but they are forced to initialize via createClerkRequest
.
I find that this helps me better understand what is a type vs a constructor when going through code quickly, but as I said, no strong opinions here.
This is exported under /internals so we can iterate as much as we like as for now, it's a "private" API
|
||
interface AuthenticateContextInterface extends AuthenticateRequestOptions { | ||
// header-based values | ||
sessionTokenInHeader: string | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ why do we use string | undefined
instead of ?: string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, the two variations are almost always interchangeable, with one semantic difference being that string | undefined
would mean that the prop exists in the object but is undefined (aka "something" in obj
would return true
) while ?: string
means that it might now exist at all ("something" in obj
might return false)
Here, we're initializing the values and even if some of them will be undefined
, they do exist on this
. Extremely nitpicky difference here so happy to change if you prefer the alternative syntax.
sessionToken: string | undefined; | ||
} | ||
|
||
interface AuthenticateContext extends AuthenticateContextInterface {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Why are we doing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're merging the interface with the class so we don't have to redefine the interface's props in the class it self
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense 👍. In that case, I believe we can get rid of the intermediary AuthenticateContextInterface
type (TS Playground).
This should work:
interface AuthenticateContext extends AuthenticateRequestOptions {
// all the properties defined in AuthenticateContextInterface above...
}
class AuthenticateContext {
// ...
}
packages/backend/src/tokens/types.ts
Outdated
type RequestStateParams = { | ||
publishableKey?: string; | ||
domain?: string; | ||
isSatellite?: boolean; | ||
proxyUrl?: string; | ||
signInUrl?: string; | ||
signUpUrl?: string; | ||
afterSignInUrl?: string; | ||
afterSignUpUrl?: string; | ||
}; | ||
|
||
export type AuthenticateRequestOptions = RequestStateParams & VerifyTokenOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we consolidate these two types, or are we using RequestStateParams
independently somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for spotting that, done!
A class that extends the native Request class, adds cookies helpers and a normalised clerkUrl that is constructed by using the values found in req.headers so it is able to work reliably when the app is running behind a proxy server.
A class that collects all data required to authenticate a request
c9a44ac
to
700c7e5
Compare
700c7e5
to
99906da
Compare
Description
Review by PR
Checklist
npm test
runs as expected.npm run build
runs as expected.Type of change
Packages affected
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/clerk-expo
@clerk/fastify
gatsby-plugin-clerk
@clerk/localizations
@clerk/nextjs
@clerk/clerk-react
@clerk/remix
@clerk/clerk-sdk-node
@clerk/shared
@clerk/themes
@clerk/types
build/tooling/chore