1 of 15

Authentication

and Authorization

Systems development and frameworks

Lecturer: Robert Schäfer

2 of 15

Frontend

Backend

Database

API

Devops

Mobile

Web

Authentication and Authorization are one of the most important responsibilities of the backend

3 of 15

jwt.io: inspect any JWT

4 of 15

Client

Server

Login

Sign token using a symmetric (or asymmetric) algorithm

Request with

Bearer token

Verify JWT with secret

(or public key)

5 of 15

Auth0 scenario

Client

Server

Login

Sign token using an asymmetric algorithm

Request with

Bearer token

Verify JWT with public key

3rd party

6 of 15

DO

Verify and decode JWT

in context function

import { JWT_SECRET } from './config.js'

import jwt from 'jsonwebtoken'

export default function context ({ req }) {

let token = req.headers.authorization || ''

token = token.replace('Bearer ', '')

try {

const decodedJwt = jwt.verify(

token,

JWT_SECRET

)

return { decodedJwt }

} catch (e) {

return {}

}

}

7 of 15

Grapqhl-middleware: adds execution layer before and after your resolvers

“unmaintained” warning as of November 23rd 2020

8 of 15

Functional programming with graphql-shield

const isAuthenticated = rule({ cache: 'contextual' })(

async (parent, args, { dataSources }, info) => {

return !!dataSources.db.currentUser()

},

)

export default shield({

Mutation: {

addFruitToBasket: isAuthenticated,

}

})

9 of 15

First method call

const isAuthenticated = rule({ cache: 'contextual' })(

async (parent, args, { dataSources }, info) => {

return !!dataSources.db.currentUser()

},

)

export default shield({

Mutation: {

addFruitToBasket: isAuthenticated,

}

})

10 of 15

Second method call

const isAuthenticated = rule({ cache: 'contextual' })(

async (parent, args, { dataSources }, info) => {

return !!dataSources.db.currentUser()

},

)

export default shield({

Mutation: {

addFruitToBasket: isAuthenticated,

}

})

11 of 15

This method argument is a callback

const isAuthenticated = rule({ cache: 'contextual' })(

async (parent, args, { dataSources }, info) => {

return !!dataSources.db.currentUser()

},

)

export default shield({

Mutation: {

addFruitToBasket: isAuthenticated,

}

})

12 of 15

Return value must be yet another method

const isAuthenticated = rule({ cache: 'contextual' })(

async (parent, args, { dataSources }, info) => {

return !!dataSources.db.currentUser()

},

)

export default shield({

Mutation: {

addFruitToBasket: isAuthenticated,

}

})

13 of 15

DO

Authorize write access

as soon as possible

export default shield({

Query: {

'*': deny,

Category: allow,

notifications: isAuthenticated,

// ...

},

Mutation: {

'*': deny,

login: allow,

UpdateUser: onlyYourself,

CreatePost: isAuthenticated,

UpdatePost: isAuthor,

DeletePost: isAuthor,

// ...

}

})

14 of 15

DO

Authorize read access

in type resolvers

export default shield({

Query: {

// ...

},

Mutation: {

// ...

},

User: {

email: or(isMyOwn, isAdmin),

},

})

15 of 15

Exam questions

  • What’s the difference between authentication and authorization?
  • Is JWT used for authentication or authorization?
  • Is graphql-shield used for authentication or authorization?
  • What’s the purpose of the three parts of a JWT encoded token?
  • Why shouldn’t you put sensitive information into a JWT token?