Repository: cornflourblue/react-jwt-authentication-example
Branch: master
Commit: 4d4f1d9f3afa
Files: 24
Total size: 16.9 KB
Directory structure:
gitextract_vywxl4o3/
├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── src/
│ ├── App/
│ │ ├── App.jsx
│ │ └── index.js
│ ├── HomePage/
│ │ ├── HomePage.jsx
│ │ └── index.js
│ ├── LoginPage/
│ │ ├── LoginPage.jsx
│ │ └── index.js
│ ├── _components/
│ │ ├── PrivateRoute.jsx
│ │ └── index.js
│ ├── _helpers/
│ │ ├── auth-header.js
│ │ ├── fake-backend.js
│ │ ├── handle-response.js
│ │ ├── history.js
│ │ └── index.js
│ ├── _services/
│ │ ├── authentication.service.js
│ │ ├── index.js
│ │ └── user.service.js
│ ├── index.html
│ └── index.jsx
└── webpack.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": [
"@babel/preset-react",
"@babel/preset-env"
]
}
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
typings
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Jason Watmore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# react-jwt-authentication-example
React (without Redux) - JWT Authentication Tutorial & Example
To see a demo and further details go to http://jasonwatmore.com/post/2019/04/06/react-jwt-authentication-tutorial-example
================================================
FILE: package.json
================================================
{
"name": "react-jwt-authentication-example",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "https://github.com/cornflourblue/react-jwt-authentication-example.git"
},
"license": "MIT",
"scripts": {
"start": "webpack-dev-server --open"
},
"dependencies": {
"formik": "^1.5.2",
"history": "^4.9.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
"rxjs": "^6.3.3",
"yup": "^0.27.0"
},
"devDependencies": {
"@babel/core": "^7.4.3",
"@babel/preset-env": "^7.4.3",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.5",
"html-webpack-plugin": "^3.2.0",
"path": "^0.12.7",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
}
================================================
FILE: src/App/App.jsx
================================================
import React from 'react';
import { Router, Route, Link } from 'react-router-dom';
import { history } from '@/_helpers';
import { authenticationService } from '@/_services';
import { PrivateRoute } from '@/_components';
import { HomePage } from '@/HomePage';
import { LoginPage } from '@/LoginPage';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentUser: null
};
}
componentDidMount() {
authenticationService.currentUser.subscribe(x => this.setState({ currentUser: x }));
}
logout() {
authenticationService.logout();
history.push('/login');
}
render() {
const { currentUser } = this.state;
return (
<Router history={history}>
<div>
{currentUser &&
<nav className="navbar navbar-expand navbar-dark bg-dark">
<div className="navbar-nav">
<Link to="/" className="nav-item nav-link">Home</Link>
<a onClick={this.logout} className="nav-item nav-link">Logout</a>
</div>
</nav>
}
<div className="jumbotron">
<div className="container">
<div className="row">
<div className="col-md-6 offset-md-3">
<PrivateRoute exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
</div>
</div>
</div>
</div>
</div>
</Router>
);
}
}
export { App };
================================================
FILE: src/App/index.js
================================================
export * from './App';
================================================
FILE: src/HomePage/HomePage.jsx
================================================
import React from 'react';
import { userService, authenticationService } from '@/_services';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
currentUser: authenticationService.currentUserValue,
users: null
};
}
componentDidMount() {
userService.getAll().then(users => this.setState({ users }));
}
render() {
const { currentUser, users } = this.state;
return (
<div>
<h1>Hi {currentUser.firstName}!</h1>
<p>You're logged in with React & JWT!!</p>
<h3>Users from secure api end point:</h3>
{users &&
<ul>
{users.map(user =>
<li key={user.id}>{user.firstName} {user.lastName}</li>
)}
</ul>
}
</div>
);
}
}
export { HomePage };
================================================
FILE: src/HomePage/index.js
================================================
export * from './HomePage';
================================================
FILE: src/LoginPage/LoginPage.jsx
================================================
import React from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { authenticationService } from '@/_services';
class LoginPage extends React.Component {
constructor(props) {
super(props);
// redirect to home if already logged in
if (authenticationService.currentUserValue) {
this.props.history.push('/');
}
}
render() {
return (
<div>
<div className="alert alert-info">
Username: test<br />
Password: test
</div>
<h2>Login</h2>
<Formik
initialValues={{
username: '',
password: ''
}}
validationSchema={Yup.object().shape({
username: Yup.string().required('Username is required'),
password: Yup.string().required('Password is required')
})}
onSubmit={({ username, password }, { setStatus, setSubmitting }) => {
setStatus();
authenticationService.login(username, password)
.then(
user => {
const { from } = this.props.location.state || { from: { pathname: "/" } };
this.props.history.push(from);
},
error => {
setSubmitting(false);
setStatus(error);
}
);
}}
render={({ errors, status, touched, isSubmitting }) => (
<Form>
<div className="form-group">
<label htmlFor="username">Username</label>
<Field name="username" type="text" className={'form-control' + (errors.username && touched.username ? ' is-invalid' : '')} />
<ErrorMessage name="username" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<Field name="password" type="password" className={'form-control' + (errors.password && touched.password ? ' is-invalid' : '')} />
<ErrorMessage name="password" component="div" className="invalid-feedback" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary" disabled={isSubmitting}>Login</button>
{isSubmitting &&
<img src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
}
</div>
{status &&
<div className={'alert alert-danger'}>{status}</div>
}
</Form>
)}
/>
</div>
)
}
}
export { LoginPage };
================================================
FILE: src/LoginPage/index.js
================================================
export * from './LoginPage';
================================================
FILE: src/_components/PrivateRoute.jsx
================================================
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { authenticationService } from '@/_services';
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => {
const currentUser = authenticationService.currentUserValue;
if (!currentUser) {
// not logged in so redirect to login page with the return url
return <Redirect to={{ pathname: '/login', state: { from: props.location } }} />
}
// authorised so return component
return <Component {...props} />
}} />
)
================================================
FILE: src/_components/index.js
================================================
export * from './PrivateRoute';
================================================
FILE: src/_helpers/auth-header.js
================================================
import { authenticationService } from '@/_services';
export function authHeader() {
// return authorization header with jwt token
const currentUser = authenticationService.currentUserValue;
if (currentUser && currentUser.token) {
return { Authorization: `Bearer ${currentUser.token}` };
} else {
return {};
}
}
================================================
FILE: src/_helpers/fake-backend.js
================================================
export function configureFakeBackend() {
let users = [{ id: 1, username: 'test', password: 'test', firstName: 'Test', lastName: 'User' }];
let realFetch = window.fetch;
window.fetch = function (url, opts) {
const isLoggedIn = opts.headers['Authorization'] === 'Bearer fake-jwt-token';
return new Promise((resolve, reject) => {
// wrap in timeout to simulate server api call
setTimeout(() => {
// authenticate - public
if (url.endsWith('/users/authenticate') && opts.method === 'POST') {
const params = JSON.parse(opts.body);
const user = users.find(x => x.username === params.username && x.password === params.password);
if (!user) return error('Username or password is incorrect');
return ok({
id: user.id,
username: user.username,
firstName: user.firstName,
lastName: user.lastName,
token: 'fake-jwt-token'
});
}
// get users - secure
if (url.endsWith('/users') && opts.method === 'GET') {
if (!isLoggedIn) return unauthorised();
return ok(users);
}
// pass through any requests not handled above
realFetch(url, opts).then(response => resolve(response));
// private helper functions
function ok(body) {
resolve({ ok: true, text: () => Promise.resolve(JSON.stringify(body)) })
}
function unauthorised() {
resolve({ status: 401, text: () => Promise.resolve(JSON.stringify({ message: 'Unauthorised' })) })
}
function error(message) {
resolve({ status: 400, text: () => Promise.resolve(JSON.stringify({ message })) })
}
}, 500);
});
}
}
================================================
FILE: src/_helpers/handle-response.js
================================================
import { authenticationService } from '@/_services';
export function handleResponse(response) {
return response.text().then(text => {
const data = text && JSON.parse(text);
if (!response.ok) {
if ([401, 403].indexOf(response.status) !== -1) {
// auto logout if 401 Unauthorized or 403 Forbidden response returned from api
authenticationService.logout();
location.reload(true);
}
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
return data;
});
}
================================================
FILE: src/_helpers/history.js
================================================
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();
================================================
FILE: src/_helpers/index.js
================================================
export * from './auth-header';
export * from './fake-backend';
export * from './handle-response';
export * from './history';
================================================
FILE: src/_services/authentication.service.js
================================================
import { BehaviorSubject } from 'rxjs';
import config from 'config';
import { handleResponse } from '@/_helpers';
const currentUserSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('currentUser')));
export const authenticationService = {
login,
logout,
currentUser: currentUserSubject.asObservable(),
get currentUserValue () { return currentUserSubject.value }
};
function login(username, password) {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
};
return fetch(`${config.apiUrl}/users/authenticate`, requestOptions)
.then(handleResponse)
.then(user => {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
currentUserSubject.next(user);
return user;
});
}
function logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
currentUserSubject.next(null);
}
================================================
FILE: src/_services/index.js
================================================
export * from './authentication.service';
export * from './user.service';
================================================
FILE: src/_services/user.service.js
================================================
import config from 'config';
import { authHeader, handleResponse } from '@/_helpers';
export const userService = {
getAll
};
function getAll() {
const requestOptions = { method: 'GET', headers: authHeader() };
return fetch(`${config.apiUrl}/users`, requestOptions).then(handleResponse);
}
================================================
FILE: src/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React - JWT Authentication Tutorial & Example</title>
<!-- bootstrap css -->
<link href="//netdna.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />
<style>
a { cursor: pointer; }
</style>
</head>
<body>
<div id="app"></div>
<!-- credits -->
<div class="text-center">
<p>
<a href="http://jasonwatmore.com/post/2019/04/06/react-jwt-authentication-tutorial-example" target="_top">React - JWT Authentication Tutorial with Example</a>
</p>
<p>
<a href="http://jasonwatmore.com" target="_top">JasonWatmore.com</a>
</p>
</div>
</body>
</html>
================================================
FILE: src/index.jsx
================================================
import React from 'react';
import { render } from 'react-dom';
import { App } from './App';
// setup fake backend
import { configureFakeBackend } from './_helpers';
configureFakeBackend();
render(
<App />,
document.getElementById('app')
);
================================================
FILE: webpack.config.js
================================================
var HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader'
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'@': path.resolve(__dirname, 'src/'),
}
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})],
devServer: {
historyApiFallback: true
},
externals: {
// global app config object
config: JSON.stringify({
apiUrl: 'http://localhost:4000'
})
}
}
gitextract_vywxl4o3/ ├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── src/ │ ├── App/ │ │ ├── App.jsx │ │ └── index.js │ ├── HomePage/ │ │ ├── HomePage.jsx │ │ └── index.js │ ├── LoginPage/ │ │ ├── LoginPage.jsx │ │ └── index.js │ ├── _components/ │ │ ├── PrivateRoute.jsx │ │ └── index.js │ ├── _helpers/ │ │ ├── auth-header.js │ │ ├── fake-backend.js │ │ ├── handle-response.js │ │ ├── history.js │ │ └── index.js │ ├── _services/ │ │ ├── authentication.service.js │ │ ├── index.js │ │ └── user.service.js │ ├── index.html │ └── index.jsx └── webpack.config.js
SYMBOL INDEX (19 symbols across 8 files)
FILE: src/App/App.jsx
class App (line 10) | class App extends React.Component {
method constructor (line 11) | constructor(props) {
method componentDidMount (line 19) | componentDidMount() {
method logout (line 23) | logout() {
method render (line 28) | render() {
FILE: src/HomePage/HomePage.jsx
class HomePage (line 5) | class HomePage extends React.Component {
method constructor (line 6) | constructor(props) {
method componentDidMount (line 15) | componentDidMount() {
method render (line 19) | render() {
FILE: src/LoginPage/LoginPage.jsx
class LoginPage (line 7) | class LoginPage extends React.Component {
method constructor (line 8) | constructor(props) {
method render (line 17) | render() {
FILE: src/_helpers/auth-header.js
function authHeader (line 3) | function authHeader() {
FILE: src/_helpers/fake-backend.js
function configureFakeBackend (line 1) | function configureFakeBackend() {
FILE: src/_helpers/handle-response.js
function handleResponse (line 3) | function handleResponse(response) {
FILE: src/_services/authentication.service.js
method currentUserValue (line 12) | get currentUserValue () { return currentUserSubject.value }
function login (line 15) | function login(username, password) {
function logout (line 33) | function logout() {
FILE: src/_services/user.service.js
function getAll (line 8) | function getAll() {
Condensed preview — 24 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (19K chars).
[
{
"path": ".babelrc",
"chars": 85,
"preview": "{\n \"presets\": [\n \"@babel/preset-react\",\n \"@babel/preset-env\"\n ]\n}"
},
{
"path": ".gitignore",
"chars": 585,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscov"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2019 Jason Watmore\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 220,
"preview": "# react-jwt-authentication-example\n\nReact (without Redux) - JWT Authentication Tutorial & Example\n\nTo see a demo and fur"
},
{
"path": "package.json",
"chars": 886,
"preview": "{\n \"name\": \"react-jwt-authentication-example\",\n \"version\": \"1.0.0\",\n \"repository\": {\n \"type\": \"git\",\n "
},
{
"path": "src/App/App.jsx",
"chars": 1868,
"preview": "import React from 'react';\nimport { Router, Route, Link } from 'react-router-dom';\n\nimport { history } from '@/_helpers'"
},
{
"path": "src/App/index.js",
"chars": 22,
"preview": "export * from './App';"
},
{
"path": "src/HomePage/HomePage.jsx",
"chars": 996,
"preview": "import React from 'react';\n\nimport { userService, authenticationService } from '@/_services';\n\nclass HomePage extends Re"
},
{
"path": "src/HomePage/index.js",
"chars": 27,
"preview": "export * from './HomePage';"
},
{
"path": "src/LoginPage/LoginPage.jsx",
"chars": 4328,
"preview": "import React from 'react';\nimport { Formik, Field, Form, ErrorMessage } from 'formik';\nimport * as Yup from 'yup';\n\nimpo"
},
{
"path": "src/LoginPage/index.js",
"chars": 28,
"preview": "export * from './LoginPage';"
},
{
"path": "src/_components/PrivateRoute.jsx",
"chars": 627,
"preview": "import React from 'react';\r\nimport { Route, Redirect } from 'react-router-dom';\r\n\r\nimport { authenticationService } from"
},
{
"path": "src/_components/index.js",
"chars": 32,
"preview": "export * from './PrivateRoute';\n"
},
{
"path": "src/_helpers/auth-header.js",
"chars": 347,
"preview": "import { authenticationService } from '@/_services';\n\nexport function authHeader() {\n // return authorization header "
},
{
"path": "src/_helpers/fake-backend.js",
"chars": 2077,
"preview": "export function configureFakeBackend() {\n let users = [{ id: 1, username: 'test', password: 'test', firstName: 'Test'"
},
{
"path": "src/_helpers/handle-response.js",
"chars": 629,
"preview": "import { authenticationService } from '@/_services';\n\nexport function handleResponse(response) {\n return response.tex"
},
{
"path": "src/_helpers/history.js",
"chars": 95,
"preview": "import { createBrowserHistory } from 'history';\n\nexport const history = createBrowserHistory();"
},
{
"path": "src/_helpers/index.js",
"chars": 124,
"preview": "export * from './auth-header';\nexport * from './fake-backend';\nexport * from './handle-response';\nexport * from './histo"
},
{
"path": "src/_services/authentication.service.js",
"chars": 1151,
"preview": "import { BehaviorSubject } from 'rxjs';\n\nimport config from 'config';\nimport { handleResponse } from '@/_helpers';\n\ncons"
},
{
"path": "src/_services/index.js",
"chars": 74,
"preview": "export * from './authentication.service';\nexport * from './user.service';\n"
},
{
"path": "src/_services/user.service.js",
"chars": 302,
"preview": "import config from 'config';\nimport { authHeader, handleResponse } from '@/_helpers';\n\nexport const userService = {\n "
},
{
"path": "src/index.html",
"chars": 745,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>React - JWT Authentication Tutorial & Exam"
},
{
"path": "src/index.jsx",
"chars": 250,
"preview": "import React from 'react';\nimport { render } from 'react-dom';\n\nimport { App } from './App';\n\n// setup fake backend\nimpo"
},
{
"path": "webpack.config.js",
"chars": 762,
"preview": "var HtmlWebpackPlugin = require('html-webpack-plugin');\nconst path = require('path');\n\nmodule.exports = {\n mode: 'dev"
}
]
About this extraction
This page contains the full source code of the cornflourblue/react-jwt-authentication-example GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 24 files (16.9 KB), approximately 4.5k tokens, and a symbol index with 19 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.