[WIP] Basic OAuth Server Setup
For this example we will be implementing a simple OAuth server using express that will handle the initial redirect for authorization, getting the token, and refreshing a token.
This is meant to be a simple demonstration and can be a good basis for your own implementation.
const axios = require("axios");
const cookieParser = require('cookie-parser');
const express = require("express");
const app = express();
app.use(express.json());
app.use(cookieParser());
const API_BASE = "https://app.mural.co";
const config = {
clientId: "my_mural_client_id", // replace this value with your app's client ID
clientSecret: "my_mural_client_secret", // replace this value with your app's client secret
redirectUri: "http://localhost:5000/auth/token/", // this should point back to this express server
scopes: [
// put any scopes you are using in here
"murals:read",
"murals:write",
"rooms:read",
"workspaces:read",
"identity:read",
],
serverPort:5000,
authorizationUri: `${API_BASE}/api/public/v1/authorization/oauth2/`,
accessTokenUri: `${API_BASE}/api/public/v1/authorization/oauth2/token`,
refreshTokenUri: `${API_BASE}/api/public/v1/authorization/oauth2/refresh`,
};
/**
* If someone has not been authenticated, you can request a url from this endpoint to redirect them to
* first. You can optionally pass a `state` query parameter and a `redirectUri` query parameter.
* @param state
* @param redirectUri
*/
app.get(
"/auth",
/**
*
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
(req, res) => {
// decide where we are redirecting after being authenticated.
const redirectUri = req.query.redirectUri
? req.query.redirectUri.toString()
: undefined;
// is there any state that needs to be passed through the auth process
const state = req.query.state ? req.query.state.toString() : undefined;
const query = new URLSearchParams();
query.set("client_id", config.clientId);
query.set("redirect_uri", config.redirectUri);
query.set("response_type", "code");
if (state) {
query.set("state", state);
}
if (config.scopes && config.scopes.length) {
query.set("scope", config.scopes.join(" "));
}
// This will return a url string that will allow you to authenticate your app
// and it can also redirect back to your client application
res.cookie('redirectUri', redirectUri)
res.redirect(302, `${config.authorizationUri}?${query}`);
}
);
app.get(
'/auth/token',
/**
*
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async (
req,
res,
) => {
const redirectUrl = new URL(req.cookies.redirectUri || req.protocol+'://'+req.hostname+'/');
console.log(req.cookies.redirectUri, redirectUrl.href);
const payload = {
data: {
client_id: config.clientId,
client_secret: config.clientSecret,
code: req.query.code,
grant_type: 'authorization_code',
redirect_uri: req.query.redirectUri || config.redirectUri,
},
method: 'POST',
url: config.accessTokenUri
};
const response = await axios.request(payload);
if (response.status !== 200) {
throw 'token request failed';
}
redirectUrl.searchParams.set('accessToken',response.data.access_token);
redirectUrl.searchParams.set('refreshToken', response.data.refresh_token);
res.redirect(302, redirectUrl.href);
},
);
app.post(
'/auth/refresh',
/**
*
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async (req, res) => {
const payload= {
data: {
client_id: config.clientId,
client_secret: config.clientSecret,
grant_type: 'refresh_token',
refresh_token: req.body.refreshToken,
scope: config.scopes,
},
method: 'POST',
url: config.refreshTokenUri,
};
const response = await axios.request(payload);
if (response.status !== 200) {
throw 'refresh token request failed';
}
res.json({
accessToken: response.data.access_token,
refreshToken: response.data.refresh_token,
});
},
);
app.listen(config.serverPort, ()=>{
console.log(`Example app listening at http://localhost:${config.serverPort}`);
});
Updated about 3 years ago