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(auth): add typings to request contexts & bodies #821

Merged
merged 6 commits into from
Dec 14, 2022

Conversation

njlie
Copy link
Contributor

@njlie njlie commented Dec 5, 2022

Changes proposed in this pull request

  • Adds types to contexts for grant, interaction, and token endpoints.

Context

Closes #351, or more precisely, closes the reason it was reopened.

Checklist

  • Related issues linked using fixes #number
  • Tests added/updated
  • Documentation added
  • Make sure that all checks pass

@github-actions github-actions bot added pkg: auth Changes in the GNAP auth package. type: source Changes business logic labels Dec 5, 2022
}

type InteractionContext<
BodyT = never,
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like there's never a specified body type, and I don't know if it needs to be enforced as never

Suggested change
BodyT = never,

interface StartQuery {
clientName: string
clientUri: string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

clientName and clientUri should be added to the OpenAPI spec to be enforced:

interface FinishParams {
id: string
nonce: string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe StartParams and FinishParams could be consolidated into a single interface

Comment on lines 71 to 72
QueryT = ParsedUrlQuery,
ParamsT = { [key: string]: string }
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like these are always defined and don't need defaults

Suggested change
QueryT = ParsedUrlQuery,
ParamsT = { [key: string]: string }
QueryT,
ParamsT }

request: ManagementRequest<ParamsT>
}

export type CreateContext<BodyT> = GrantContext<BodyT>
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this needed? Can GrantContext just be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

GrantContext can definitely just be used, but I was following the pattern here:

export type CreateContext<BodyT> = CollectionContext<BodyT>

Comment on lines 85 to 97
type ManagementRequest<ParamsT = { [key: string]: string }> = Omit<
AppContext['request'],
'body'
> & {
params?: ParamsT
}

type ManagementContext<ParamsT = { [key: string]: string }> = Omit<
AppContext,
'request'
> & {
request: ManagementRequest<ParamsT>
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
type ManagementRequest<ParamsT = { [key: string]: string }> = Omit<
AppContext['request'],
'body'
> & {
params?: ParamsT
}
type ManagementContext<ParamsT = { [key: string]: string }> = Omit<
AppContext,
'request'
> & {
request: ManagementRequest<ParamsT>
}
type ManagementRequest<ParamsT = { [key: string]: string }> = Omit<
AppContext['request'],
'params'
> & {
params: Record<'id', string>
}
export type ManagementContext = Omit<
AppContext,
'request'
> & {
request: ManagementRequest
}

I think 👆 can replace RevokeContext, RotateContext, and ManageParams

@njlie njlie force-pushed the nl-context-body-types branch 2 times, most recently from 0ecd9a2 to c3e834e Compare December 8, 2022 19:54
@njlie njlie requested a review from wilsonianb December 8, 2022 21:52
export type IntrospectContext<BodyT> = TokenContext<BodyT>
export type RevokeContext = ManagementContext
export type RotateContext = ManagementContext

Copy link
Contributor

Choose a reason for hiding this comment

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

The calls to createValidatorMiddleware below should specify the type guarded context.
For example:

this.publicRouter.post(
'/',
createValidatorMiddleware(openApi.authServerSpec, {
path: '/',
method: HttpMethod.POST
}),
this.config.bypassSignatureValidation
? (ctx, next) => next()
: grantInitiationHttpsigMiddleware,
grantRoutes.create
)

should change to have

      createValidatorMiddleware<CreateContext>(openApi.authServerSpec, {
        path: '/',
        method: HttpMethod.POST
      })

That gets tricky without having the particular BodyT defined in this file.
One solution is to use:

type ContextType<T> = T extends (
ctx: infer Context
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => any
? Context
: never

then have

      createValidatorMiddleware<Context<grantRoutes.create>>(openApi.authServerSpec, {
        path: '/',
        method: HttpMethod.POST
      })

in which case a lot of these contexts can be defined in their corresponding routes.ts file and be defined with the specific generic type (BodyT, etc)

path: '/',
method: HttpMethod.POST
}),
createValidatorMiddleware<ContextType<typeof grantCreate>>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we just import CreateContext and ditch ContextType + the typed grantCreate definition?

Suggested change
createValidatorMiddleware<ContextType<typeof grantCreate>>(
createValidatorMiddleware<CreateContext>(

ditto elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems like the type of ContextType and the like don't seem to be compatible unless it's cast to AppContext like in the current implementation.

Type 'CreateContext' does not satisfy the constraint 'ExtendableContext & { state: DefaultState; } & DefaultContext & { body: unknown; response: { body: unknown; }; }'.
  Type 'CreateContext' is missing the following properties from type 'ExtendableContext': app, response, req, res, and 52 more.

(alias) type CreateContext = Omit<AppContext, "request"> & {
    request: GrantRequest<GrantRequestBody, ParsedUrlQuery>;
    clientKeyId: string;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🤔
Maybe this extends Koa.ParameterizedContext is causing us more trouble than it's worth?

export function createValidatorMiddleware<T extends Koa.ParameterizedContext>(

Copy link
Contributor

Choose a reason for hiding this comment

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

either that or we should be less cavalier with Omiting parts of AppContext

export type AppRequest<ParamsT extends string = string> = Omit<
AppContext['request'],
'params'
> & {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤔 Maybe this extends Koa.ParameterizedContext is causing us more trouble than it's worth?

export function createValidatorMiddleware<T extends Koa.ParameterizedContext>(

It's caused me issues in the past when trying to add session middleware to the AS:

// Only accepts Middleware<DefaultState, DefaultContext> for some reason, this.koa is Middleware<DefaultState, AppContext>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.koa as any

Copy link
Contributor

Choose a reason for hiding this comment

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

I vote we remove the extends Koa.ParameterizedContext in openapi's createValidatorMiddleware (assuming that makes using our desired contexts possible)

(I'm not sure if that will help with your previous session type issue though.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems like the general issue is that Koa.ParameterizedContext doesn't seem to produce a type that's assignable to the base Koa context, or that at least the session middleware doesn't expect it as a possible type for a koa context.

All for removing extends Koa.ParameterizedContext if it works, though. It'll at least lift that restriction for the validator middleware.

Copy link
Contributor

Choose a reason for hiding this comment

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

Meanwhile, renovates over here saying: "Help me help you!"

(I don't know if it'll help)

@njlie njlie force-pushed the nl-context-body-types branch 2 times, most recently from ceceb1d to b85f3d9 Compare December 12, 2022 23:46
@njlie njlie force-pushed the nl-context-body-types branch from b85f3d9 to 20ff4fd Compare December 12, 2022 23:56
Comment on lines 209 to 215
const {
create: grantCreate,
continue: grantContinue
}: {
create: (ctx: AppContext) => Promise<void>
continue: (ctx: AppContext) => Promise<void>
} = grantRoutes
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these can be removed

Suggested change
const {
create: grantCreate,
continue: grantContinue
}: {
create: (ctx: AppContext) => Promise<void>
continue: (ctx: AppContext) => Promise<void>
} = grantRoutes

@njlie njlie merged commit ac84eb1 into main Dec 14, 2022
@njlie njlie deleted the nl-context-body-types branch December 14, 2022 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: auth Changes in the GNAP auth package. type: source Changes business logic
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Validate GNAP requests with OpenAPI
2 participants