Search code examples
reactjsauthenticationjwtauth0express-jwt

JWT why can I bypass authentication?


I am following this auth0 tutorial for a react/express + jwt webpage.

Everything seems ok. Login/logout, accessing secure page all good.

Except I can bypass the login with a fake token. If I just go to jwt.io and generate a token that hasn't expired yet, I can access the secure page without actually logging in. What am I missing here?

This is the part of the code that handles authentication:

./utils/AuthService.js
const ID_TOKEN_KEY = 'id_token';
const ACCESS_TOKEN_KEY = 'access_token';

const CLIENT_ID = 'auht0 client id';
const CLIENT_DOMAIN = 'foo.eu.auth0.com';
const REDIRECT = 'http://localhost:3000/callback';
const SCOPE = 'openid profile ';
const AUDIENCE = 'https://foo.eu.auth0.com/api/v2/';

var auth = new auth0.WebAuth({
  clientID: CLIENT_ID,
  domain: CLIENT_DOMAIN
});

export function login() {
  auth.authorize({
    responseType: 'token id_token',
    redirectUri: REDIRECT,
    audience: AUDIENCE,
    scope: SCOPE
  });
}

export function logout() {
  clearIdToken();
  clearAccessToken();
  browserHistory.push('/');
}

export function requireAuth(nextState, replace) {
  if (!isLoggedIn()) {
    replace({pathname: '/'});
  }
}

export function getIdToken() {
  return localStorage.getItem(ID_TOKEN_KEY);
}

export function getAccessToken() {
  return localStorage.getItem(ACCESS_TOKEN_KEY);
}

function clearIdToken() {
  localStorage.removeItem(ID_TOKEN_KEY);
}

function clearAccessToken() {
  localStorage.removeItem(ACCESS_TOKEN_KEY);
}

// Helper function that will allow us to extract the access_token and id_token
function getParameterByName(name) {
  let match = RegExp('[#&]' + name + '=([^&]*)').exec(window.location.hash);
  return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

// Get and store access_token in local storage
export function setAccessToken() {
  let accessToken = getParameterByName('access_token');
  localStorage.setItem(ACCESS_TOKEN_KEY, accessToken);
}

// Get and store id_token in local storage
export function setIdToken() {
  let idToken = getParameterByName('id_token');
  localStorage.setItem(ID_TOKEN_KEY, idToken);
}

export function isLoggedIn() {
  const idToken = getIdToken();
  return !!idToken && !isTokenExpired(idToken);
}

function getTokenExpirationDate(encodedToken) {
  const token = decode(encodedToken);
  if (!token.exp) { return null; }

  const date = new Date(0);
  date.setUTCSeconds(token.exp);

  return date;
}

function isTokenExpired(token) {
  const expirationDate = getTokenExpirationDate(token);
  return expirationDate < new Date();
}

Solution

  • The part you've posted just stores / retrieves the token from the local storage. The authentication itself is handled on the server side

      secret: jwks.expressJwtSecret({
            cache: true,
            rateLimit: true,
            jwksRequestsPerMinute: 5,
            // YOUR-AUTH0-DOMAIN name e.g prosper.auth0.com
            jwksUri: "https://{YOUR-AUTH0-DOMAIN}/.well-known/jwks.json"
        }),
        // This is the identifier we set when we created the API
        audience: '{YOUR-API-AUDIENCE-ATTRIBUTE}',
        issuer: '{YOUR-AUTH0-DOMAIN}',
        algorithms: ['RS256']
    });
    

    The sever-side funtionality MUST check the JWT token signature. Without the private key you won't be able to generate a valid signature of the JWT token.

    If you really can bypass the authentication, it means the server has serious security issue (the signature is not properly validated). Maybe for test/demo services it is not implemented.