Java Web Tokens: Difference between revisions
Line 146: | Line 146: | ||
path: '/refresh_token', | path: '/refresh_token', | ||
}) | }) | ||
} | |||
</syntaxhighlight> | |||
==Authorization== | |||
Read the bearer token, must ask the next Swedish person to say this. | |||
<syntaxhighlight lang="js"> | |||
const isAuth = req => { | |||
const authorisation = req.headers['authorization'] | |||
if(!authorisation) throw new Error("User must login") | |||
const token = authorisation.split(' ')[1] | |||
const {userId} = verify(token, process.env.ACCESS_TOKEN_SECRET) | |||
return userId | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 23:36, 31 March 2021
Introduction
Java Web Tokens are used for Authorisation and Information Exchange. They consist of three parts, a header, Payload and a Signature. For example
Format
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Example
Refresh Tokens
When the use authenticates they are provided with an access token. The user can then request a new access token with a refresh token. The access token typically has a much shorter lifespan.
The key question when working on this was where to store the refresh token. After all it enables you to get an access token. In the NodeJS example I use HttpOnly cookie which seemed to be ok. https://owasp.org/www-community/HttpOnly
NodeJS Example
This is not production code and should not be used as such
End Points
Login
Here is the code for logging in. The use is stored in an array. The access token and refresh token are created.
// Login user
server.post('/login', async (req,res) => {
const {email, password} = req.body
try {
// Check if user exists
const user = fakeDB.find(user => user.email === email)
if(!user) throw new Error('User does not exists')
const valid = await compare(password, user.password)
if(!valid) throw new Error('Password or user incorrect')
// Create Access and Refresh token
const accessToken = createAccessToken(user.id)
const refreshAccessToken = createRefreshAccessToken(user.id)
// Puts the refresh access token in database
user.refreshAccessToken = refreshAccessToken
console.log(fakeDB)
// Sends refresh access token as a cookie
// Sends access token in header
sendRefreshAccessToken(res,refreshAccessToken)
sendAccessToken(req,res,accessToken)
}
catch(exp) {
res.send({error: exp.message})
}
})
Logout
The cookie is cleared
server.post('/logout', async (req,res) => {
res.clearCookie('refreshtoken',{ path: '/refresh_token'})
return res.send(
{
'message': 'User has logged out',
})
})
Refresh
Create a new access token using the refresh token
server.post('/refresh_token', async (req,res) => {
const token = req.cookies.refreshtoken
if (!token) return res.send({accessToken: ''})
let payload = null
// Check as have a token and it is verified
try {
payload = verify(token, process.env.REFRESH_TOKEN_SECRET)
}
catch(exp) {
return res.send({accessToken: ''})
}
// Extract the user from the payload and check it exists
const user = fakeDB.find(user => user.id === payload.userId)
if (!user ||user.refreshAccessToken !== token)
return res.send({accessToken: ''})
// Token exists, create a new refresh and access token
const accessToken = createAccessToken(user.id)
const refreshAccessToken = createRefreshAccessToken(user.id)
user.refreshAccessToken = refreshAccessToken
// Send to User as cookie and regular response
sendRefreshAccessToken(res,refreshAccessToken)
return res.send({accessToken})
})
Token Creation
The nodejs uses jsonwebtoken
const createAccessToken = userId => {
return sign(
{userId},
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '15m'})
}
const createRefreshAccessToken = userId => {
return sign(
{userId},
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '7d'})
}
const sendAccessToken = (req, res, accessToken) => {
res.send({
accessToken,
email:req.body.email
})
}
const sendRefreshAccessToken = (res, refreshAccessToken) => {
res.cookie('refreshtoken', refreshAccessToken, {
httpOnly: true,
path: '/refresh_token',
})
}
Authorization
Read the bearer token, must ask the next Swedish person to say this.
const isAuth = req => {
const authorisation = req.headers['authorization']
if(!authorisation) throw new Error("User must login")
const token = authorisation.split(' ')[1]
const {userId} = verify(token, process.env.ACCESS_TOKEN_SECRET)
return userId
}