enable cors

master
Peter Babič 5 years ago
parent 835aaea901
commit 316d8c524f
Signed by: peter.babic
GPG Key ID: 4BB075BC1884BA40
  1. 128
      src/server.spec.ts
  2. 58
      src/server.ts

@ -10,66 +10,72 @@ import { User } from "./server/userResolver/User"
import cookie = require("cookie") import cookie = require("cookie")
describe("server should", () => { describe("server should", () => {
it("perform the refresh tokens operation flawlessly", async () => { it("perform the refresh tokens operation flawlessly", async () => {
const halfADay = (60 * 60 * 24) / 2 const halfADay = (60 * 60 * 24) / 2
const fifteenDays = 60 * 60 * 24 * 15 const fifteenDays = 60 * 60 * 24 * 15
const createUserResponse = await rawRequest(gqlUri, gqlToStr(createUserMutation)) const createUserResponse = await rawRequest(gqlUri, gqlToStr(createUserMutation))
const userId = createUserResponse.data.createUser.id const userId = createUserResponse.data.createUser.id
const accessTokenReponse = await rawRequest(gqlUri, gqlToStr(accessTokenQuery)) const accessTokenReponse = await rawRequest(gqlUri, gqlToStr(accessTokenQuery))
const accessToken: string = accessTokenReponse.data.accessToken const accessToken: string = accessTokenReponse.data.accessToken
const headers: Headers = accessTokenReponse.headers const headers: Headers = accessTokenReponse.headers
const cookieHeader = headers.get("set-cookie") as string const cookieHeader = headers.get("set-cookie") as string
const parsedCookie = cookie.parse(cookieHeader) const varyHeader = headers.get("vary") as string
const refreshCookieExpires = dateInKiloSeconds(parsedCookie.Expires) const acacHeader = headers.get("access-control-allow-credentials") as string
const refreshTokenPayload = verifiedRefreshTokenPayload(parsedCookie.rt) const acaoHeader = headers.get("access-control-allow-origin") as string
const jwtLifetime = refreshTokenPayload.exp! - refreshTokenPayload.iat! const parsedCookie = cookie.parse(cookieHeader)
const refLifetime = dateInKiloSeconds(new Date().getTime() + jwtLifetime * 1000) const refreshCookieExpires = dateInKiloSeconds(parsedCookie.Expires)
const refreshTokenPayload = verifiedRefreshTokenPayload(parsedCookie.rt)
const jwtLifetime = refreshTokenPayload.exp! - refreshTokenPayload.iat!
const refLifetime = dateInKiloSeconds(new Date().getTime() + jwtLifetime * 1000)
const client = new GraphQLClient(gqlUri, { const client = new GraphQLClient(gqlUri, {
headers: { headers: {
Authorization: "Bearer " + accessToken, Authorization: "Bearer " + accessToken,
}, },
}) })
const meResponse = await client.rawRequest(gqlToStr(meQuery)) const meResponse = await client.rawRequest(gqlToStr(meQuery))
const refreshTokenResponse = await fetch(refreshTokenUri, { const refreshTokenResponse = await fetch(refreshTokenUri, {
method: "POST", method: "POST",
headers: { cookie: cookieHeader }, headers: { cookie: cookieHeader },
}) })
const jsonResponse = await refreshTokenResponse.json() const jsonResponse = await refreshTokenResponse.json()
expect(cookieHeader).toMatch(/HttpOnly/) expect(varyHeader).toBe("Origin")
expect(parsedCookie.Path).toBe("/refresh_token") expect(acacHeader).toBe("true")
expect(refreshTokenPayload.userId).toBe(userId) expect(acaoHeader).toMatch(/http:/)
expect(refreshCookieExpires).toBeCloseTo(refLifetime) expect(cookieHeader).toMatch(/HttpOnly/)
expect(jwtLifetime).toBeGreaterThanOrEqual(halfADay) expect(parsedCookie.Path).toBe("/refresh_token")
expect(jwtLifetime).not.toBeGreaterThan(fifteenDays) expect(refreshTokenPayload.userId).toBe(userId)
expect(meResponse.data.me.email).toBe("auth@server.com") expect(refreshCookieExpires).toBeCloseTo(refLifetime)
expect(jsonResponse.data).toBeDefined() expect(jwtLifetime).toBeGreaterThanOrEqual(halfADay)
expect(jsonResponse.errors).toBeUndefined() expect(jwtLifetime).not.toBeGreaterThan(fifteenDays)
}) expect(meResponse.data.me.email).toBe("auth@server.com")
expect(jsonResponse.data).toBeDefined()
expect(jsonResponse.errors).toBeUndefined()
})
it("it doesnt perform refresh tokens without valid cookie", async () => { it("it doesnt perform refresh tokens without valid cookie", async () => {
const response = await fetch(refreshTokenUri, { const response = await fetch(refreshTokenUri, {
method: "POST", method: "POST",
headers: { cookie: "INVALID-COOKIE" }, headers: { cookie: "INVALID-COOKIE" },
}) })
const jsonResponse = await response.json() const jsonResponse = await response.json()
expect(jsonResponse.data).toBeNull() expect(jsonResponse.data).toBeNull()
expect(jsonResponse.errors).not.toBeUndefined() expect(jsonResponse.errors).not.toBeUndefined()
}) })
}) })
beforeAll(async () => { beforeAll(async () => {
await createConnection(testingConnectionOptions()) await createConnection(testingConnectionOptions())
await createServer(port) await createServer(port)
}) })
afterAll(async () => { afterAll(async () => {
User.delete({ email: "auth@server.com" }) User.delete({ email: "auth@server.com" })
}) })
const port = 4001 const port = 4001
@ -77,26 +83,26 @@ const gqlUri = `http://localhost:${port}/graphql`
const refreshTokenUri = `http://localhost:${port}/refresh_token` const refreshTokenUri = `http://localhost:${port}/refresh_token`
const createUserMutation = gql` const createUserMutation = gql`
mutation { mutation {
createUser(email: "auth@server.com", password: "password") { createUser(email: "auth@server.com", password: "password") {
email email
id id
} }
} }
` `
const accessTokenQuery = gql` const accessTokenQuery = gql`
query { query {
accessToken(email: "auth@server.com", password: "password") accessToken(email: "auth@server.com", password: "password")
} }
` `
const meQuery = gql` const meQuery = gql`
query { query {
me { me {
email email
} }
} }
` `
const dateInKiloSeconds = (date: string | number) => new Date(date).getTime() / 1000000 const dateInKiloSeconds = (date: string | number) => new Date(date).getTime() / 1000000

@ -2,34 +2,44 @@ import express = require("express")
import { ApolloServer } from "apollo-server-express" import { ApolloServer } from "apollo-server-express"
import { createSchema } from "./server/schema" import { createSchema } from "./server/schema"
import { import {
accessTokenWithRefreshCookie, accessTokenWithRefreshCookie,
contextFunction, contextFunction,
verifiedRefreshTokenPayload, verifiedRefreshTokenPayload,
} from "./server/userResolver/auth" } from "./server/userResolver/auth"
import cookie = require("cookie") import cookie = require("cookie")
import cors = require("cors")
export const createServer = async (port: number) => { export const createServer = async (port: number) => {
const server = new ApolloServer({ const server = new ApolloServer({
schema: await createSchema(), schema: await createSchema(),
playground: true, playground: true,
introspection: true, introspection: true,
debug: true, debug: true,
context: contextFunction, context: contextFunction,
}) })
const app = express() const app = express()
app.post("/refresh_token", (req, res) => { app.use(
try { cors({
const parsedCookie = cookie.parse(req.headers.cookie!) origin: "http://localhost:3000",
const refreshPayload = verifiedRefreshTokenPayload(parsedCookie.rt) credentials: true,
const accessToken = accessTokenWithRefreshCookie(refreshPayload.userId, res) })
res.json({ data: accessToken }) )
} catch (error) {
res.json({ data: null, errors: "Refresh failed: " + error })
}
})
server.applyMiddleware({ app })
app.listen({ port })
return server app.post("/refresh_token", (req, res) => {
try {
const parsedCookie = cookie.parse(req.headers.cookie!)
const refreshPayload = verifiedRefreshTokenPayload(parsedCookie.rt)
const accessToken = accessTokenWithRefreshCookie(refreshPayload.userId, res)
res.json({ data: accessToken })
} catch (error) {
res.json({ data: null, errors: "Refresh failed: " + error })
}
})
server.applyMiddleware({ app, cors: false })
app.listen({ port })
return server
} }

Loading…
Cancel
Save