Search code examples
javascriptnode.jsaxiosoauthauth0

Unable to fetch userinfo using access_token from auth0


I am trying to build a simple authentication library, and I am using axios instead of library built by auth0. I am unable to fetch the userdata using the access code. I am also using google provider for authentication.

import axios from 'axios'

export default class Auth {
    constructor(
        private domain: string,
        private client_id: string,
        private redirect_uri: string
    ) {}

    startAuthFlow(): string {
        const params = new URLSearchParams({
            response_type: 'code',
            client_id: this.client_id,
            redirect_uri: this.redirect_uri,
            scope: 'offline_access'
        })
        const authURI = `https://${this.domain}/authorize?${params.toString()}`
        return authURI
    }

    async handleCallback(code: string) {
        return await this.exchangeCodeForToken(code)
    }

    async getUserInfo(accessToken: string) {
        const userInfoEndpoint = `https://${this.domain}/userinfo`
        try {
            const response = await axios.get(userInfoEndpoint, {
                params: {
                    scope: "openid profile email"
                },
                headers: {
                    Authorization: `Bearer ${accessToken}`
                }
            })
            return response.data
        } catch (error) {
            throw error
        }
    }

    async refreshToken(refresh_token: string) {
        const tokenEndpoint = `https://${this.domain}/oauth/token`
        const payload = {
            grant_type: 'refresh_token',
            client_id: this.client_id,
            refresh_token
        }
        try {
            const response = await axios.post(tokenEndpoint, payload, {
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            return response.data
        } catch (error) {
            throw error
        }
    }

    private async exchangeCodeForToken(code: string) {
        const tokenEndPoint = `https://${this.domain}/oauth/token`
        const payload = {
            grant_type: 'authorization_code',
            client_id: this.client_id,
            client_secret: '[my client secret]',
            code,
            redirect_uri: this.redirect_uri,
            scope: 'openid profile email'
        }
        try {
            const reponse = await axios.post(tokenEndPoint, payload)
            const { access_token, id_token, refresh_token } = reponse.data
            return { access_token, id_token, refresh_token }
        } catch (error) {
            throw error
        }
    }
}


I am using this library in a express application to test it.

const express = require('express')
const Auth = require('../auth').default
const auth = new Auth('[domain].us.auth0.com', '[client ID]', 'http://localhost:3000/callback')

const app = new express()

app.get('/', (req,res) => {
    return res.send('Hello')
})

app.get('/login', (req, res) => {
    res.redirect(auth.startAuthFlow())
})

app.get('/callback', async (req, res) => {
    const { code } = req.query
    try {
        const { access_token } = await auth.handleCallback(code)
        console.log(access_token)
        const user = await auth.getUserInfo(access_token)
        console.log("USER: ", user)

        res.redirect('/')
    } catch (error) {
        console.log(error)
        return res.status(404).send(error)
    }
})

app.listen(3000, () => {
    console.log('Server running on port 3000')
})

Can anyone help me why I am not able to fetch the user data? I can see the userdata in my auth0 dashboard enter image description here


Solution

  • You missed

    Extracted both user.name and user.email from the user object

    Your program is functionally correct in fetching the user's information (including their name and email) after the login process.

    .env

    AUTH0_DOMAIN=[your-domain].us.auth0.com
    AUTH0_CLIENT_ID=[Your CLIENT ID]
    AUTH0_CLIENT_SECRET=[Your CLIENT SECRET]
    AUTH0_REDIRECT_URI=http://localhost:3000/callback
    PORT=3000
    

    tsconfig.json

    {
      "compilerOptions": {
        "target": "es2016",
        "module": "commonjs",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true
      }
    }
    

    package.json

    {
      "dependencies": {
        "axios": "^1.7.9",
        "dotenv": "^16.4.7",
        "express": "^4.21.2"
      },
      "devDependencies": {
        "typescript": "^5.7.2"
      }
    }
    

    clinet.ts

    import axios from 'axios'
    
    export default class Auth {
        constructor(
            private domain: string,
            private client_id: string,
            private redirect_uri: string,
            private client_secret: string
        ) {}
    
        startAuthFlow(): string {
            const params = new URLSearchParams({
                response_type: 'code',
                client_id: this.client_id,
                redirect_uri: this.redirect_uri,
                scope: 'openid profile email offline_access'
            });
            const authURI = `https://${this.domain}/authorize?${params.toString()}`;
            return authURI;
        }
    
        async handleCallback(code: string) {
            return await this.exchangeCodeForToken(code);
        }
    
        async getUserInfo(accessToken: string) {
            const userInfoEndpoint = `https://${this.domain}/userinfo`;
            try {
                const response = await axios.get(userInfoEndpoint, {
                    headers: {
                        Authorization: `Bearer ${accessToken}`
                    }
                });
                return response.data;
            } catch (error) {
                throw new Error(`Failed to fetch user info: ${error}`);
            }
        }
    
        async refreshToken(refresh_token: string) {
            const tokenEndpoint = `https://${this.domain}/oauth/token`;
            const payload = {
                grant_type: 'refresh_token',
                client_id: this.client_id,
                refresh_token
            };
            try {
                const response = await axios.post(tokenEndpoint, payload, {
                    headers: {
                        'Content-Type': 'application/json'
                    }
                });
                return response.data;
            } catch (error) {
                throw new Error(`Failed to refresh token: ${error}`);
            }
        }
    
        private async exchangeCodeForToken(code: string) {
            const tokenEndPoint = `https://${this.domain}/oauth/token`;
            const payload = {
                grant_type: 'authorization_code',
                client_id: this.client_id,
                client_secret: this.client_secret,
                code,
                redirect_uri: this.redirect_uri
            };
            try {
                const response = await axios.post(tokenEndPoint, payload, {
                    headers: {
                        'Content-Type': 'application/json'
                    }
                });
                const { access_token, id_token, refresh_token } = response.data;
                return { access_token, id_token, refresh_token };
            } catch (error) {
                throw new Error(`Failed to exchange code for token: ${error}`);
            }
        }
    }
    
    

    server.js

    require('dotenv').config();
    const express = require('express');
    const Auth = require('./client').default;
    
    const auth = new Auth(
        process.env.AUTH0_DOMAIN,
        process.env.AUTH0_CLIENT_ID,
        process.env.AUTH0_REDIRECT_URI,
        process.env.AUTH0_CLIENT_SECRET
    );
    
    const app = express();
    
    app.use(express.json());
    
    // CORS Middleware (optional, for frontend integration)
    app.use((req, res, next) => {
        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
        next();
    });
    
    app.get('/', (req, res) => {
        return res.send('Hello, Auth0 Demo!');
    });
    
    app.get('/login', (req, res) => {
        res.redirect(auth.startAuthFlow());
    });
    
    app.get('/callback', async (req, res) => {
        const { code } = req.query;
        try {
            const { access_token } = await auth.handleCallback(code);
            const user = await auth.getUserInfo(access_token);
            console.log('User Info:', user);
    
            // Extract the user's name and email
            const userName = user.name || 'Unknown User';
            const userEmail = user.email || 'No email provided';
    
            // Send the response with user details
            res.send(`
                <h1>Welcome, ${userName}!</h1>
                <p>Email: ${userEmail}</p>
                <p>User information has been logged to the console.</p>
            `);
        } catch (error) {
            console.error(error);
            res.status(500).send('Authentication failed');
        }
    });
    
    
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
        console.log(`Server running on port ${PORT}`);
    });
    
    

    Install dependencies

    npm install
    

    To compile client.ts

    tsc
    

    Run server.js

    node server.js
    

    Login by browser

    http://localhost:3000/login
    

    Result

    enter image description here