Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
feat: add a onSubscriptionConnect function to to security service for…
Browse files Browse the repository at this point in the history
… handling auth in subscriptions
  • Loading branch information
Dara Hayes committed May 16, 2019
1 parent 0e37291 commit d12868f
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
27 changes: 23 additions & 4 deletions packages/voyager-keycloak/src/KeycloakSecurityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,28 @@ export class KeycloakSecurityService implements SecurityService {
}
}

public async validateToken(token: string): Promise<boolean> {
const tokenObject = getTokenObject(token)
const result = await this.keycloak.grantManager.validateToken(tokenObject, 'Bearer')
return (result === tokenObject) ? true : false
public async onSubscriptionConnect(connectionParams: any, webSocket: any, context: any): Promise<any> {
let header = connectionParams.Authorization
|| connectionParams.authorization
|| connectionParams.Auth
|| connectionParams.auth
if (!header) {
throw new Error('Access Denied - missing Authorization field in connection parameters')
}
const token = this.getBearerTokenFromHeader(header)
try {
await this.keycloak.grantManager.validateToken(token, 'Bearer')
return token
} catch (e) {
this.log.error(`Error validating token from connectionParam ${header}\n${e}`)
throw new Error(`Access Denied - ${e}`)
}
}

private getBearerTokenFromHeader(header: any) {
if (header && typeof header === 'string' && (header.indexOf('bearer ') === 0 || header.indexOf('Bearer ') === 0)) {
const token = header.substring(7)
return getTokenObject(token)
}
}
}
4 changes: 4 additions & 0 deletions packages/voyager-keycloak/src/api/DefaultSecurityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export class DefaultSecurityService implements SecurityService {
public getAuthContextProvider () {
return DefaultAuthContextProvider
}

public onSubscriptionConnect() {
return new Promise((resolve, reject) => resolve())
}
}

export class DefaultAuthContextProvider implements AuthContextProvider {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface Logger {
info(...args: any[]): void
error(...args: any[]): void
}

export interface KeycloakSecurityServiceOptions {
Expand Down
15 changes: 15 additions & 0 deletions packages/voyager-keycloak/src/api/SecurityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,19 @@ export interface SecurityService {
* Like hapi, koa, fastify, etc.
*/
applyAuthMiddleware (expressApp: Router, options: any): void

/**
* onSubscriptionConnect is called when a client opens a websocket connection
* for a GraphQL subscription. Anything returned from this function is added
* to the context within subscription resolvers
* The main use case here is auth. Example - we could parse and validate a token
* from the connectionParams and return a user object. Now this object is accessible
* Within the subscription context.
* Apollo docs: https://www.apollographql.com/docs/graphql-subscriptions/authentication
*
* @param connectionParams connection parameters provided by the websocket client
* @param webSocket The websocket object
* @param context
*/
onSubscriptionConnect(connectionParams: any, webSocket: any, context: any): Promise<any>
}

0 comments on commit d12868f

Please sign in to comment.