Sign In via CLI Server
Start a local callback server in your CLI and authenticate with vuer-auth using the OIDC flow. This method is ideal for CLI tools and scripts that need user authentication.
Overview
This authentication method works by:
- Starting a local HTTP server with a callback endpoint
- Opening the browser for user authentication
- Receiving the access token via the callback endpoint
- Storing the token for future use
Important: The callback endpoint must be named
/sign-in
Important: The callback server must run on port
3012
Note: See Verify JWT for how to parse JWT tokens
Prerequisites
Install the required dependencies:
npm install express cors open
Implementation
1. Create the Sign-In Server Script
Create a file named signin.js with the following code:
// signin.js
import express from "express";
import open from "open";
import cors from "cors";
import * as fs from "node:fs";
import path from "node:path";
// Configuration
const PORT = 3012; // MUST be 3012 for vuer-auth OIDC flow
const TOKEN_PATH = path.join(process.cwd(), ".vuer_token");
const AUTH_SERVER = "https://staging-auth.vuer.ai";
const app = express();
// Enable CORS for the auth server
app.use(
cors({
origin: [`http://localhost:${PORT}`, AUTH_SERVER],
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
credentials: true,
}),
);
// IMPORTANT: Callback endpoint must be named "/sign-in"
app.get("/sign-in", (req, res) => {
const { access_token } = req.query ?? {};
if (!access_token) {
console.log("❌ Login failed. No access token received.");
res.send("error");
process.exit(1);
}
try {
// Save the access token to file
fs.writeFileSync(TOKEN_PATH, access_token);
console.log(`✅ Login successful!`);
console.log(`✅ Token saved to ${TOKEN_PATH}`);
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Authentication Successful</title>
<style>
body { font-family: sans-serif; text-align: center; padding: 50px; }
h1 { color: #4CAF50; }
</style>
</head>
<body>
<h1>✓ Authentication Successful!</h1>
<p>You can now close this window and return to the CLI.</p>
</body>
</html>
`);
// Close the server after a short delay
setTimeout(() => {
console.log("🔒 Shutting down callback server...");
process.exit(0);
}, 1000);
} catch (error) {
console.error("❌ Failed to save token:", error.message);
res.send("error");
process.exit(1);
}
});
// Start the server
console.log("🔐 Vuer Auth CLI Login");
console.log("=".repeat(50));
app.listen(PORT, async () => {
console.log("🚀 Starting OIDC authentication flow...");
console.log(`📡 Callback server listening on http://localhost:${PORT}`);
// Construct the callback URL - must use /sign-in endpoint on port 3012
const callbackUrl = `http://localhost:${PORT}/sign-in`;
const authUrl = `${AUTH_SERVER}/authorize?clientApi=${encodeURIComponent(callbackUrl)}`;
console.log(`🌐 Opening browser for authentication...`);
console.log(` Auth URL: ${authUrl}`);
console.log(` Callback URL: ${callbackUrl}`);
try {
// Open the authentication page in the default browser
await open(authUrl);
console.log("⏳ Waiting for authentication...");
} catch (error) {
console.error("❌ Failed to open browser:", error.message);
console.log(`\nPlease manually open this URL in your browser:`);
console.log(authUrl);
}
});
// Handle server errors
app.on("error", (error) => {
if (error.code === "EADDRINUSE") {
console.error(`❌ Port ${PORT} is already in use!`);
console.error(` Please ensure no other process is using port ${PORT}.`);
} else {
console.error("❌ Server error:", error.message);
}
process.exit(1);
});
2. Run the Authentication Script
Execute the script to start the OIDC authentication flow:
node signin.js
You will see output similar to:
🔐 Vuer Auth CLI Login
==================================================
🚀 Starting OIDC authentication flow...
📡 Callback server listening on http://localhost:3012
🌐 Opening browser for authentication...
Auth URL: https://staging-auth.vuer.ai/authorize?clientApi=http%3A%2F%2Flocalhost%3A3012%2Fsign-in
Callback URL: http://localhost:3012/sign-in
⏳ Waiting for authentication...
3. Complete Authentication in Browser
The script will automatically open your default browser to the authentication page. Follow these steps:
- Sign in or register with your credentials
- Grant permissions if prompted
- Wait for the success message in the browser
- The token will be automatically saved and the server will shut down
You should see in the CLI:
✅ Login successful!
✅ Token saved to /path/to/your/project/.vuer_token
🔒 Shutting down callback server...
Configuration Options
Change Token Storage Path
Modify the TOKEN_PATH constant to store the token in a different location:
// Store in user's home directory
const TOKEN_PATH = path.join(process.env.HOME, ".config", "vuer", "token");
// Store in system temp directory
const TOKEN_PATH = path.join(os.tmpdir(), ".vuer_token");
// Store with a custom name
const TOKEN_PATH = path.join(process.cwd(), ".my-app-token");
Change Auth Server
To use a different authentication server:
const AUTH_SERVER = "https://your-auth-server.com";
Warning: The port cannot be changed. It must be
3012for the vuer-auth OIDC flow to work correctly.
Using the Token
After successful authentication, the access token is saved to .vuer_token. You can read and use it in your application:
Read the Token
import * as fs from "node:fs";
import path from "node:path";
const TOKEN_PATH = path.join(process.cwd(), ".vuer_token");
try {
const token = fs.readFileSync(TOKEN_PATH, "utf-8");
console.log("Token:", token);
} catch (error) {
console.error("Failed to read token:", error.message);
console.log("Please run the sign-in script first.");
}
Make Authenticated API Requests
import * as fs from "node:fs";
import path from "node:path";
const TOKEN_PATH = path.join(process.cwd(), ".vuer_token");
const token = fs.readFileSync(TOKEN_PATH, "utf-8");
// Use the token in API requests
const response = await fetch("https://api.example.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
const user = await response.json();
console.log("User:", user);
Verify and Parse the JWT Token
See the Verify JWT documentation to learn how to verify the token signature and extract user information.
Error Handling
Port Already in Use
If port 3012 is already in use, the script will fail with an error:
❌ Port 3012 is already in use!
Please ensure no other process is using port 3012.
To resolve this:
- Find the process using port 3012:
lsof -i :3012(macOS/Linux) ornetstat -ano | findstr :3012(Windows) - Stop the process or wait for it to finish
- Run the authentication script again
Browser Doesn't Open
If the browser fails to open automatically, you'll see:
❌ Failed to open browser: [error message]
Please manually open this URL in your browser:
https://staging-auth.vuer.ai/authorize?clientApi=...
Copy and paste the URL into your browser manually.
Authentication Failed
If authentication fails or is cancelled:
❌ Login failed. No access token received.
Try running the script again.
Security Considerations
-
Token Storage
- The token is stored in plain text in
.vuer_token - Add
.vuer_tokento your.gitignoreto prevent committing it - Consider using secure storage mechanisms for production
- The token is stored in plain text in
-
Fixed Port Requirement
- Port 3012 is required by the vuer-auth OIDC flow
- Ensure this port is available before running the script
- The callback URL must be
http://localhost:3012/sign-in
-
Localhost Only
- This method only works with localhost callback URLs
- The callback server should only accept connections from localhost
- Never expose port 3012 to the internet
-
Token Lifetime
- Access tokens may expire after a certain period
- Implement token refresh logic if needed
- Check token expiration before making API requests
-
HTTPS in Production
- For production use, consider using HTTPS for the callback server
- Or use a different authentication method suitable for production
Complete Example with Token Refresh
Here's a more complete example that checks if a token exists and is valid:
import express from "express";
import open from "open";
import cors from "cors";
import * as fs from "node:fs";
import path from "node:path";
import { jwtVerify, createRemoteJWKSet } from "jose";
const PORT = 3012; // MUST be 3012 for vuer-auth OIDC flow
const TOKEN_PATH = path.join(process.cwd(), ".vuer_token");
const AUTH_SERVER = "https://staging-auth.vuer.ai";
const JWKS_URL = `${AUTH_SERVER}/.well-known/jwks.json`;
// Check if token exists and is valid
async function checkExistingToken() {
if (!fs.existsSync(TOKEN_PATH)) {
return false;
}
try {
const token = fs.readFileSync(TOKEN_PATH, "utf-8");
const jwks = createRemoteJWKSet(new URL(JWKS_URL));
await jwtVerify(token, jwks, { algorithms: ["EdDSA"] });
return true;
} catch (error) {
console.log("⚠️ Existing token is invalid or expired");
return false;
}
}
// Main function
async function main() {
console.log("🔐 Vuer Auth CLI Login");
console.log("=".repeat(50));
// Check if we already have a valid token
const hasValidToken = await checkExistingToken();
if (hasValidToken) {
console.log("✅ Already authenticated!");
console.log(`📄 Token file: ${TOKEN_PATH}`);
process.exit(0);
}
console.log("🔓 No valid token found. Starting authentication...");
// ... rest of the authentication flow (see full example above)
}
main();
See Also
- Sign In via Device Flow - Alternative CLI authentication method for headless environments
- Verify JWT - How to verify and parse JWT tokens
- Basic Usage - Client-side authentication guide