11import fs from "fs" ;
22import path from "path" ;
33import { fileURLToPath } from "url" ;
4+ import { globalState , log } from "./index.js" ;
45// Replace __dirname with import.meta.url
56const __filename = fileURLToPath ( import . meta. url ) ;
67const __dirname = path . dirname ( __filename ) ;
@@ -10,33 +11,33 @@ const wait = (milliseconds) => {
1011} ;
1112const fetchDynamic = async ( ) => ( await import ( "node-fetch" ) ) . default ;
1213const TOKEN_FILE = path . resolve ( __dirname , "token.json" ) ;
13- // Update authState to use the AuthState interface
1414export const authState = {
1515 deviceCode : "" ,
1616 verificationUri : "" ,
1717 userCode : "" ,
1818 clientId : process . env . CLIENT_ID || "0oabtxactgS3gHIR0297" ,
1919} ;
20- // Update functions to use authState and globalState
21- import { globalState } from "./index.js" ;
2220export async function authenticate ( ) {
23- console . log ( "Starting authentication process..." ) ;
21+ log ( "info" , "Starting authentication process..." ) ;
2422 const authUrl = "https://cloud.mongodb.com/api/private/unauth/account/device/authorize" ;
25- console . log ( "Client ID:" , authState . clientId ) ;
23+ log ( "info" , ` Client ID: ${ authState . clientId } ` ) ;
2624 const deviceCodeResponse = await ( await fetchDynamic ( ) ) ( authUrl , {
2725 method : "POST" ,
2826 headers : {
2927 "Content-Type" : "application/x-www-form-urlencoded" ,
28+ "Accept" : "application/json" ,
29+ "User-Agent" : `AtlasMCP/${ process . env . VERSION } (${ process . platform } ; ${ process . arch } ; ${ process . env . HOSTNAME || "unknown" } )` ,
3030 } ,
3131 body : new URLSearchParams ( {
3232 client_id : authState . clientId ,
33- scope : "openid" ,
33+ scope : "openid profile offline_access" ,
34+ grant_type : "urn:ietf:params:oauth:grant-type:device_code" ,
3435 } ) . toString ( ) ,
3536 } ) ;
3637 const responseText = await deviceCodeResponse . text ( ) ;
37- console . log ( "Device Code Response Body:" , responseText ) ;
38+ log ( "info" , ` Device Code Response Body: ${ responseText } ` ) ;
3839 if ( ! deviceCodeResponse . ok ) {
39- console . error ( " Failed to initiate authentication:" , deviceCodeResponse . statusText ) ;
40+ log ( "error" , ` Failed to initiate authentication: ${ deviceCodeResponse . statusText } ` ) ;
4041 throw new Error ( `Failed to initiate authentication: ${ deviceCodeResponse . statusText } ` ) ;
4142 }
4243 const deviceCodeData = JSON . parse ( responseText ) ;
@@ -49,7 +50,7 @@ export async function authenticate() {
4950 } ;
5051}
5152export async function pollToken ( ) {
52- console . log ( "Starting token polling process..." ) ;
53+ log ( "info" , "Starting token polling process..." ) ;
5354 if ( ! authState . deviceCode ) {
5455 throw new Error ( "Device code not found. Please initiate authentication first." ) ;
5556 }
@@ -70,7 +71,7 @@ export async function pollToken() {
7071 } ) . toString ( ) ,
7172 } ) ;
7273 const responseText = await OAuthToken . text ( ) ;
73- console . log ( "Token Response Body:" , responseText ) ;
74+ log ( "info" , ` Token Response Body: ${ responseText } ` ) ;
7475 if ( OAuthToken . ok ) {
7576 const tokenData = JSON . parse ( responseText ) ;
7677 globalState . auth = true ;
@@ -79,9 +80,9 @@ export async function pollToken() {
7980 }
8081 else {
8182 const errorResponse = JSON . parse ( responseText ) ;
82- console . error ( " Token polling error:" , errorResponse . error ) ;
83+ log ( "error" , ` Token polling error: ${ errorResponse . error } ` ) ;
8384 if ( errorResponse . errorCode === "DEVICE_AUTHORIZATION_PENDING" ) {
84- console . log ( "Device authorization is pending. Please try again later." ) ;
85+ log ( "info" , "Device authorization is pending. Please try again later." ) ;
8586 continue ;
8687 }
8788 else if ( errorResponse . error === "expired_token" ) {
@@ -96,28 +97,27 @@ export async function pollToken() {
9697}
9798export function saveToken ( token ) {
9899 fs . writeFileSync ( TOKEN_FILE , JSON . stringify ( { token } ) ) ;
99- console . log ( "Token saved to file." ) ;
100+ log ( "info" , "Token saved to file." ) ;
100101}
101- export function loadToken ( ) {
102+ export function getToken ( ) {
103+ if ( ! authState . token ) {
104+ loadToken ( ) ;
105+ }
106+ return authState . token ;
107+ }
108+ function loadToken ( ) {
102109 if ( fs . existsSync ( TOKEN_FILE ) ) {
103110 const data = JSON . parse ( fs . readFileSync ( TOKEN_FILE , "utf-8" ) ) ;
104- authState . token = data ;
111+ authState . token = data . token ;
105112 globalState . auth = true ;
106- console . log ( "Token loaded from file." ) ;
113+ log ( "info" , "Token loaded from file." ) ;
114+ return data ;
107115 }
116+ return undefined ;
108117}
109- // Update getAuthStateData to return a typed object
110- export function getAuthStateData ( ) {
111- return {
112- deviceCode : authState . deviceCode ,
113- verificationUri : authState . verificationUri ,
114- userCode : authState . userCode ,
115- clientId : authState . clientId ,
116- } ;
117- }
118- // Extend isAuthenticated to validate and refresh the token
118+ // Check if token exists, if it's valid and refreshes it if necessary
119119export async function isAuthenticated ( ) {
120- console . log ( "Checking authentication status..." ) ;
120+ log ( "info" , "Checking authentication status..." ) ;
121121 if ( globalState . auth ) {
122122 return true ;
123123 }
@@ -130,7 +130,7 @@ export async function isAuthenticated() {
130130 }
131131 // Validate the existing token
132132 try {
133- const isValid = await validateToken ( authState . token . access_token ) ;
133+ const isValid = await validateToken ( authState . token ) ;
134134 if ( isValid ) {
135135 return true ;
136136 }
@@ -144,44 +144,67 @@ export async function isAuthenticated() {
144144 }
145145 }
146146 catch ( error ) {
147- console . error ( " Error during token validation or refresh:" , error ) ;
147+ log ( "error" , ` Error during token validation or refresh: ${ error } ` ) ;
148148 }
149149 globalState . auth = false ;
150150 return false ;
151151}
152- // Helper function to validate the token
153- async function validateToken ( token ) {
152+ async function validateToken ( tokenData ) {
154153 try {
155- const tokenData = JSON . parse ( fs . readFileSync ( TOKEN_FILE , "utf-8" ) ) ;
156154 const expiryDate = new Date ( tokenData . expiry ) ;
157155 return expiryDate > new Date ( ) ; // Token is valid if expiry is in the future
158156 }
159157 catch ( error ) {
160- console . error ( " Error validating token:" , error ) ;
158+ log ( "error" , ` Error validating token: ${ error } ` ) ;
161159 return false ;
162160 }
163161}
164- // Update the code to cast 'data' to OAuthToken
165162async function refreshToken ( token ) {
166163 try {
167164 const response = await ( await fetchDynamic ( ) ) ( "https://cloud.mongodb.com/api/private/unauth/account/device/token" , {
168165 method : "POST" ,
169166 headers : {
170167 "Content-Type" : "application/x-www-form-urlencoded" ,
168+ "Accept" : "application/json" ,
169+ "User-Agent" : `AtlasMCP/${ process . env . VERSION } (${ process . platform } ; ${ process . arch } ; ${ process . env . HOSTNAME || "unknown" } )` ,
171170 } ,
172171 body : new URLSearchParams ( {
173172 client_id : authState . clientId ,
174173 refresh_token : token ,
175174 grant_type : "refresh_token" ,
175+ scope : "openid profile offline_access" ,
176176 } ) . toString ( ) ,
177177 } ) ;
178178 if ( response . ok ) {
179- const data = ( await response . json ( ) ) ; // Explicit cast here
179+ const data = ( await response . json ( ) ) ;
180180 return data ;
181181 }
182182 }
183183 catch ( error ) {
184- console . error ( " Error refreshing token:" , error ) ;
184+ log ( "error" , ` Error refreshing token: ${ error } ` ) ;
185185 }
186186 return null ;
187187}
188+ async function revokeToken ( token ) {
189+ try {
190+ const response = await ( await fetchDynamic ( ) ) ( "https://cloud.mongodb.com/api/private/unauth/account/device/revoke" , {
191+ method : "POST" ,
192+ headers : {
193+ "Content-Type" : "application/x-www-form-urlencoded" ,
194+ "Accept" : "application/json" ,
195+ "User-Agent" : `AtlasMCP/${ process . env . VERSION } (${ process . platform } ; ${ process . arch } ; ${ process . env . HOSTNAME || "unknown" } )` ,
196+ } ,
197+ body : new URLSearchParams ( {
198+ client_id : authState . clientId ,
199+ token,
200+ token_type_hint : "refresh_token" ,
201+ } ) . toString ( ) ,
202+ } ) ;
203+ if ( ! response . ok ) {
204+ log ( "error" , `Failed to revoke token: ${ response . statusText } ` ) ;
205+ }
206+ }
207+ catch ( error ) {
208+ log ( "error" , `Error revoking token: ${ error } ` ) ;
209+ }
210+ }
0 commit comments