Index: pom.xml
===================================================================
--- pom.xml	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ pom.xml	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -68,4 +68,26 @@
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-oauth2-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-api</artifactId>
+            <version>0.11.5</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+            <version>0.11.5</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
+            <version>0.11.5</version>
+            <scope>runtime</scope>
+        </dependency>
 
     </dependencies>
Index: src/main/java/com/zinemasterapp/zinemasterapp/controller/AuthController.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/controller/AuthController.java	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ src/main/java/com/zinemasterapp/zinemasterapp/controller/AuthController.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -3,4 +3,5 @@
 
 import com.zinemasterapp.zinemasterapp.dto.LoginRequest;
+import com.zinemasterapp.zinemasterapp.dto.UserDTO;
 import com.zinemasterapp.zinemasterapp.model.PasswordResetToken;
 import com.zinemasterapp.zinemasterapp.model.User;
@@ -10,4 +11,5 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -17,9 +19,11 @@
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.token.TokenService;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
 
 import javax.naming.AuthenticationException;
@@ -112,5 +116,33 @@
     }
 
+    @GetMapping( "/me")//(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE) drug nacin,isto e samo sto forcame da vrakja json
+    public ResponseEntity<UserDTO> me(@AuthenticationPrincipal UserDetails userDetails) {//ova e od spring security i go rpoveruva tokenot
+        if (userDetails == null) {
+            return ResponseEntity.status(401).build();
+        }
 
+        User user = userRepository.findByUsername(userDetails.getUsername())
+                .orElseThrow(() -> new UsernameNotFoundException("User not found"));
+
+        System.out.println(userDetails.getUsername());
+
+        UserDTO dto = new UserDTO(
+                user.getId(),
+                user.getUsername(),
+                user.getName(),
+                user.getSurname(),
+                user.getEmail(),
+                user.getEmailVerified(),
+                user.getAuthProvider(),
+                user.getGoogleSub(),
+                user.getProfilePic(),
+                user.getAddress(),
+                user.getStartDate(),
+                user.getUserType(),
+                user.getAccess()
+        );
+        System.out.println("I am sending my dto");
+        return ResponseEntity.ok(dto);
+    }
 
 }
Index: src/main/java/com/zinemasterapp/zinemasterapp/dto/UserDTO.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/dto/UserDTO.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ src/main/java/com/zinemasterapp/zinemasterapp/dto/UserDTO.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,143 @@
+package com.zinemasterapp.zinemasterapp.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.time.LocalDate;
+
+public class UserDTO {
+    private String id;
+    private String username;
+    private String name;
+    private String surname;
+    private String email;
+    private boolean emailVerified;
+    private String authProvider;
+    private String googleSub;
+    private String profilePic;
+    private String address;
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
+    private String startDate;
+    private String userType;
+    private int access;
+
+    public UserDTO(String id, String username, String name, String surname, String email, Boolean emailVerified, String authProvider, String googleSub, String profilePic, String address, LocalDate startDate, String userType, int access) {
+        this.id = id;
+        this.username = username;
+        this.name = name;
+        this.surname = surname;
+        this.email = email;
+        this.emailVerified = emailVerified;
+        this.authProvider = authProvider;
+        this.googleSub = googleSub;
+        this.profilePic = profilePic;
+        this.address = address;
+        this.startDate = startDate.toString();
+        this.userType = userType;
+        this.access = access;
+
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSurname() {
+        return surname;
+    }
+
+    public void setSurname(String surname) {
+        this.surname = surname;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public boolean isEmailVerified() {
+        return emailVerified;
+    }
+
+    public void setEmailVerified(boolean emailVerified) {
+        this.emailVerified = emailVerified;
+    }
+
+    public String getAuthProvider() {
+        return authProvider;
+    }
+
+    public void setAuthProvider(String authProvider) {
+        this.authProvider = authProvider;
+    }
+
+    public String getGoogleSub() {
+        return googleSub;
+    }
+
+    public void setGoogleSub(String googleSub) {
+        this.googleSub = googleSub;
+    }
+
+    public String getProfilePic() {
+        return profilePic;
+    }
+
+    public void setProfilePic(String profilePic) {
+        this.profilePic = profilePic;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(String startDate) {
+        this.startDate = startDate;
+    }
+
+    public String getUserType() {
+        return userType;
+    }
+
+    public void setUserType(String userType) {
+        this.userType = userType;
+    }
+
+    public int getAccess() {
+        return access;
+    }
+
+    public void setAccess(int access) {
+        this.access = access;
+    }
+}
Index: src/main/java/com/zinemasterapp/zinemasterapp/model/User.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/model/User.java	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ src/main/java/com/zinemasterapp/zinemasterapp/model/User.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -39,4 +39,32 @@
     @Column(nullable = false, unique = true)
     private String email;
+
+    private String googleSub;
+    private Boolean emailVerified;
+    private String authProvider;
+
+    public String getGoogleSub() {
+        return googleSub;
+    }
+
+    public void setGoogleSub(String googleSub) {
+        this.googleSub = googleSub;
+    }
+
+    public Boolean getEmailVerified() {
+        return emailVerified;
+    }
+
+    public void setEmailVerified(Boolean emailVerified) {
+        this.emailVerified = emailVerified;
+    }
+
+    public String getAuthProvider() {
+        return authProvider;
+    }
+
+    public void setAuthProvider(String authProvider) {
+        this.authProvider = authProvider;
+    }
 
     public String getEmail() {
Index: src/main/java/com/zinemasterapp/zinemasterapp/repository/UserRepository.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/repository/UserRepository.java	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ src/main/java/com/zinemasterapp/zinemasterapp/repository/UserRepository.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -8,4 +8,5 @@
 public interface UserRepository extends JpaRepository<User, String> {//a spingboot JPA interface so i can use all kinds of functions
     Optional<User> findByUsername(String username);//SELECT * FROM users WHERE username = ?, in the background
+    Optional<User> findByEmail(String email);
 }
 
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/JwtAuthenticationFilter.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/JwtAuthenticationFilter.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/JwtAuthenticationFilter.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,63 @@
+package com.zinemasterapp.zinemasterapp.security;
+
+
+import com.zinemasterapp.zinemasterapp.security.jwt.JwtService;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Component
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
+
+    private final JwtService jwtService;
+    private final UserDetailsService userDetailsService;
+
+    public JwtAuthenticationFilter(JwtService jwtService, UserDetailsService userDetailsService) {
+        this.jwtService = jwtService;
+        this.userDetailsService = userDetailsService;//service sto go vrakja username
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain filterChain) throws ServletException, IOException {
+
+        final String authHeader = request.getHeader("Authorization");//od zaglavje cita
+        final String jwt;
+        final String username;
+
+        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
+            filterChain.doFilter(request, response);//Authentication: Bearer,ako nema krositikot togas ostanuva anonimen
+            return;
+        }
+
+        jwt = authHeader.substring(7);
+        username = jwtService.extractUsername(jwt);
+
+        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
+            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);//ako ne  eavtenticiran
+
+            if (jwtService.isTokenValid(jwt, userDetails)) {
+                UsernamePasswordAuthenticationToken authToken =
+                        new UsernamePasswordAuthenticationToken(
+                                userDetails,
+                                null,
+                                userDetails.getAuthorities());
+                authToken.setDetails(
+                        new WebAuthenticationDetailsSource().buildDetails(request));
+                SecurityContextHolder.getContext().setAuthentication(authToken);
+            }
+        }
+        filterChain.doFilter(request, response);
+    }
+}
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/SecurityConfig.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/SecurityConfig.java	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/SecurityConfig.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -1,4 +1,7 @@
 package com.zinemasterapp.zinemasterapp.security;
 
+import com.zinemasterapp.zinemasterapp.security.oauth.OAuth2AuthenticationFailureHandler;
+import com.zinemasterapp.zinemasterapp.security.oauth.OAuth2AuthenticationSuccessHandler;
+import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -8,7 +11,9 @@
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.cors.CorsConfigurationSource;
@@ -20,4 +25,18 @@
 @EnableWebSecurity
 public class SecurityConfig {
+
+    private final OAuth2AuthenticationSuccessHandler successHandler;
+    private final OAuth2AuthenticationFailureHandler failureHandler;
+    private final JwtAuthenticationFilter jwtAuthenticationFilter;
+
+
+    public SecurityConfig(OAuth2AuthenticationSuccessHandler successHandler,
+            OAuth2AuthenticationFailureHandler failureHandler, JwtAuthenticationFilter jwtAuthenticationFilter)
+    {
+        this.successHandler = successHandler;
+        this.failureHandler = failureHandler;
+        this.jwtAuthenticationFilter = jwtAuthenticationFilter;
+    }
+
 
     @Bean
@@ -32,9 +51,13 @@
 
     @Bean
-    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
         http
                 .csrf(csrf -> csrf.disable())
-                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
+                .cors(c -> c.configurationSource(corsConfigurationSource()))
+                .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+                .exceptionHandling(ex -> ex.authenticationEntryPoint(
+                        (req, res, e) -> res.sendError(HttpServletResponse.SC_UNAUTHORIZED)))
                 .authorizeHttpRequests(auth -> auth
+                                .requestMatchers("/oauth2/**","/login/oauth2/**").permitAll()
                                 .requestMatchers(HttpMethod.POST, "/api/users").permitAll()
                         .requestMatchers(HttpMethod.PUT, "/api/users/**").permitAll()
@@ -54,9 +77,17 @@
                                 "/api/uploads/**",
                                 "/uploads/**"//ova e za da mozat da se zemat slikite
-                        ).permitAll()//samo ovie moze bez loggin se drugo mora logged in
+                        ).permitAll()
+                        .requestMatchers(HttpMethod.GET, "/api/products/**").permitAll()
+                        .requestMatchers(HttpMethod.GET, "/api/auth/**").permitAll()
+                      // .requestMatchers("/api/**").authenticated()
+                       // .anyRequest().permitAll()
                         .anyRequest().authenticated()
-                         //.anyRequest().permitAll()
+                )
+                .oauth2Login(o -> o
+                        .successHandler(successHandler)
+                        .failureHandler(failureHandler)
                 );
 
+        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
         return http.build();
     }
@@ -66,5 +97,5 @@
     public CorsConfigurationSource corsConfigurationSource() {
         CorsConfiguration config = new CorsConfiguration();
-        config.setAllowedOrigins(List.of("http://localhost:8082")); //ovde e frontendot
+        config.setAllowedOrigins(List.of("http://localhost:8082","http://192.168.0.14:8082")); //ovde e frontendot
         config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));//koj metodi gi dozvoluvame
         config.setAllowedHeaders(List.of("*"));//koj headeri gi dozvoluvame
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/jwt/JwtService.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/jwt/JwtService.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/jwt/JwtService.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,68 @@
+package com.zinemasterapp.zinemasterapp.security.jwt;
+
+import io.jsonwebtoken.*;
+import io.jsonwebtoken.security.Keys;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Service;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+
+@Service
+public class JwtService {
+
+    @Value("${app.jwt.secret}")//od applications.properties cita
+    private String secret;
+
+    @Value("${app.jwt.expiry-minutes:120}")
+    private long expiryMinutes;
+
+
+    public String createToken(String userId, String username, String role, String email) {
+        Instant now = Instant.now();//ne e dovolno detailed za so LocalDate
+        return Jwts.builder()
+                .setSubject(userId)//unique treba da e
+                .claim("username", username)//claim se kroisti za stavanje vo teloto na tokenot,username:{value}
+                .claim("role", role)
+                .claim("email", email)
+                .setIssuedAt(Date.from(now))
+                .setExpiration(Date.from(now.plus(Duration.ofMinutes(expiryMinutes))))
+                .signWith(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)), SignatureAlgorithm.HS256)//kluc
+                .compact();//go kreira krajniot token
+    }
+
+    public String extractUsername(String token) {
+
+        return getClaims(token).get("username", String.class);//toj username jas go kreirav
+    }
+
+    public boolean isTokenValid(String token, UserDetails userDetails) {
+        try {
+            final String username = extractUsername(token);
+            return username != null
+                    && username.equals(userDetails.getUsername())
+                    && !isExpired(token);
+        } catch (JwtException e) {
+            return false;
+        }
+    }
+
+
+    private boolean isExpired(String token) {
+//        Date exp = getClaims(token).getExpiration();
+//        return exp.before(new Date());
+        return getClaims(token).getExpiration().toInstant()
+                .isBefore(Instant.now());
+    }
+
+    private Claims getClaims(String token) {
+        return Jwts.parserBuilder()
+                .setSigningKey(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)))//klucot
+                .build()//pocnat e parserot
+                .parseClaimsJws(token)//gi zemame site delovi od tokenot
+                .getBody();//go zeame samo teloto
+    }
+}
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/oauth/OAuth2AuthenticationFailureHandler.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/oauth/OAuth2AuthenticationFailureHandler.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/oauth/OAuth2AuthenticationFailureHandler.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,30 @@
+package com.zinemasterapp.zinemasterapp.security.oauth;
+
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+import jakarta.servlet.ServletException;
+
+import java.io.IOException;
+
+@Component
+public class OAuth2AuthenticationFailureHandler implements AuthenticationFailureHandler {
+
+    @Value("${app.oauth2.post-login-redirect}")//od application.properties
+    private String postLoginRedirect;//kaj ke go pratime
+
+    @Override
+    public void onAuthenticationFailure(HttpServletRequest request,//koristime Servleti deka sme an low-level,del od Spring Security
+                                        HttpServletResponse response,
+                                        AuthenticationException exception) throws IOException, ServletException {
+
+        String targetUrl = postLoginRedirect + "?error=oauth_failed";
+
+        response.sendRedirect(targetUrl);//ova e nie sto prakjame
+    }
+}
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/oauth/OAuth2AuthenticationSuccessHandler.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/oauth/OAuth2AuthenticationSuccessHandler.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/oauth/OAuth2AuthenticationSuccessHandler.java	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,88 @@
+package com.zinemasterapp.zinemasterapp.security.oauth;
+
+import com.zinemasterapp.zinemasterapp.model.User;
+import com.zinemasterapp.zinemasterapp.repository.UserRepository;
+import com.zinemasterapp.zinemasterapp.security.jwt.JwtService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.Authentication;
+import jakarta.servlet.ServletException;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import jakarta.servlet.http.*;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Random;
+
+
+@Component
+public class OAuth2AuthenticationSuccessHandler implements AuthenticationSuccessHandler {
+
+    private final UserRepository userRepository;
+    private final JwtService jwtService;
+
+    @Value("${app.oauth2.post-login-redirect}")
+    private String frontendRedirect;
+
+    public OAuth2AuthenticationSuccessHandler(UserRepository userRepository, JwtService jwtService) {
+        this.userRepository = userRepository;
+        this.jwtService = jwtService;
+    }
+
+    @Override
+    public void onAuthenticationSuccess(HttpServletRequest request,
+                                        HttpServletResponse response,
+                                        Authentication authentication) throws IOException {
+        OAuth2User p = (OAuth2User) authentication.getPrincipal();//ova e toa sto Google ni ima vrateno
+
+        String email    = (String) p.getAttribute("email");
+        String name     = (String) p.getAttribute("name");
+        String picture  = (String) p.getAttribute("picture");
+        Boolean verified = (Boolean) p.getAttribute("email_verified");
+
+
+        var userOpt = userRepository.findByEmail(email);
+        if (userOpt.isEmpty()) {
+
+            String target = UriComponentsBuilder.fromUriString(frontendRedirect)
+                    .queryParam("error", "no_account_for_email")//ako ne e vo db
+                    .build(true).toUriString();
+            response.sendRedirect(target);
+            return;
+        }
+
+        User user = userOpt.get();
+
+        if (user.getAccess() == 0) {
+            String target = UriComponentsBuilder.fromUriString(frontendRedirect)
+                    .queryParam("error", "account_inactive")//ako ne e aktiven
+                    .build(true).toUriString();
+            response.sendRedirect(target);
+            return;
+        }
+
+        if (picture != null) user.setProfilePic(picture);
+        if (verified != null) user.setEmailVerified(verified);
+        user.setAuthProvider("google");
+        userRepository.save(user);
+
+
+        String jwt = jwtService.createToken(
+                user.getId(),
+                user.getUsername(),
+                user.getUserType(),
+                user.getEmail()
+        );
+
+
+        String target = UriComponentsBuilder.fromUriString(frontendRedirect)
+                .queryParam("token", jwt)//stavame kveri parametar token=...
+                .build(true).toUriString();
+
+        response.sendRedirect(target);
+    }
+
+}
Index: src/main/resources/application.properties
===================================================================
--- src/main/resources/application.properties	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ src/main/resources/application.properties	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -23,6 +23,21 @@
 spring.mail.properties.mail.smtp.starttls.enable=true
 
+spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
+spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
+spring.security.oauth2.client.registration.google.scope=openid,profile,email
+spring.security.oauth2.client.registration.google.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
+spring.security.oauth2.client.provider.google.issuer-uri=https://accounts.google.com
+
+app.oauth2.post-login-redirect=http://localhost:8082/oauth2/callback
+
+app.jwt.secret=${APP_JWT_SECRET}            
+app.jwt.expiry-minutes=120
+
+app.frontend.redirect=http://localhost:8082
+
+logging.level.org.springframework.security=DEBUG
+logging.level.org.springframework.security.oauth2=DEBUG
+logging.level.org.springframework.web.client=DEBUG
+# app.cors.allowed-origins=http://localhost:8082
 
 
-
-
Index: zinemaster-frontend/api.js
===================================================================
--- zinemaster-frontend/api.js	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ zinemaster-frontend/api.js	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,8 @@
+import axios from 'axios'
+axios.defaults.baseURL = 'http://localhost:8081'
+
+axios.interceptors.request.use(config => {
+    const t = localStorage.getItem('auth_token')
+    if (t) config.headers.Authorization = `Bearer ${t}`
+    return config
+})
Index: zinemaster-frontend/src/components/LoginPage.vue
===================================================================
--- zinemaster-frontend/src/components/LoginPage.vue	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ zinemaster-frontend/src/components/LoginPage.vue	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -38,4 +38,10 @@
 
         <button type="submit" class="btn btn-gradient w-100 mt-3">LOGIN</button>
+        <div class="text-center mt-3">
+
+          <button type="button" class="btn btn-danger w-100" @click="loginWithGoogle">
+            <i class="fab fa-google me-2"></i> Login with Google
+          </button>
+        </div>
 
         <p v-if="error" class="text-danger mt-2 text-center">{{ error }}</p>
@@ -51,4 +57,14 @@
 import axios from 'axios';
 import { useRouter } from 'vue-router';
+
+
+const loginWithGoogle = async () => {
+  try {
+
+    window.location.href = "http://localhost:8081/oauth2/authorization/google"; // goes via proxy(popravi go loso e)
+  } catch (err) {
+    console.error("Google login failed", err);
+  }
+};
 
 const username = ref('');
Index: zinemaster-frontend/src/components/OAuth2Callback.vue
===================================================================
--- zinemaster-frontend/src/components/OAuth2Callback.vue	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
+++ zinemaster-frontend/src/components/OAuth2Callback.vue	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -0,0 +1,58 @@
+<template>
+  <div class="container mt-5 pt-5 text-center">
+    <h3 v-if="errorMessage" class="text-danger">{{ errorMessage }}</h3>
+    <p v-else>Signing you in…</p>
+  </div>
+</template>
+
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import axios from 'axios'
+
+const router = useRouter()
+const errorMessage = ref(null)
+
+onMounted(async () => {
+  const params = new URLSearchParams(window.location.search)
+  const err = params.get('error')
+  const token = params.get('token')
+
+  if (err) {
+    if (err === 'no_account_for_email') {
+      errorMessage.value = 'No account found for this Google email. Please log in with username/password.'
+    } else if (err === 'account_inactive') {
+      errorMessage.value = 'Your account is inactive. Please contact support.'
+    } else if (err === 'domain_not_allowed') {
+      errorMessage.value = 'This Google domain is not allowed.'
+    } else {
+      errorMessage.value = 'Login failed. Please try again.'
+    }
+    setTimeout(() => router.replace('/login'), 2500)
+    return
+  }
+
+  if (token) {
+    localStorage.setItem('auth_token', token)
+
+    try {
+      const res = await axios.get("http://localhost:8081/api/auth/me", {
+        headers: { Authorization: `Bearer ${token}` }
+      })
+
+
+      console.log("my data")
+      console.log(res.data)
+      localStorage.setItem('user', JSON.stringify(res.data))
+      router.replace('/main')
+    } catch (e) {
+      console.error('Fetching user failed:', e)
+      router.replace('/login')
+    }
+  } else {
+    router.replace('/login')
+  }
+})
+</script>
+
Index: zinemaster-frontend/src/main.js
===================================================================
--- zinemaster-frontend/src/main.js	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ zinemaster-frontend/src/main.js	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -5,2 +5,10 @@
 
 createApp(App).use(router).mount('#app');
+const params = new URLSearchParams(window.location.search)
+const tok = params.get('token')
+if (tok) {
+    localStorage.setItem('auth_token', tok)
+    const url = new URL(window.location.href)
+    url.searchParams.delete('token')
+    window.history.replaceState({}, '', url.toString())
+}
Index: zinemaster-frontend/src/router/index.js
===================================================================
--- zinemaster-frontend/src/router/index.js	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ zinemaster-frontend/src/router/index.js	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -8,4 +8,5 @@
 import ResetPassword from '@/components/ResetPassword.vue';
 import ProductDetails from '@/components/ProductDetails.vue';
+import OAuth2Callback from '../components/OAuth2Callback.vue'
 
 const routes = [
@@ -18,5 +19,6 @@
   { path: '/forgot-password', component: ForgotPassword},
   { path: '/reset-password', component: ResetPassword},
-  { path: '/products/:id', component: ProductDetails, props: true }
+  { path: '/products/:id', component: ProductDetails, props: true },
+  { path: '/oauth2/callback', component: OAuth2Callback }
 
 ];
Index: zinemaster-frontend/vue.config.js
===================================================================
--- zinemaster-frontend/vue.config.js	(revision 68db9c9529762f0bc5c578eac5f8effa8b840c61)
+++ zinemaster-frontend/vue.config.js	(revision 73c3109dc7dc91e556d10e6a40fd45cd3ac103b0)
@@ -3,5 +3,9 @@
   transpileDependencies: true,
   devServer: {
-    port: 8082
+    port: 8082,
+    proxy: {
+      '^/api': { target: 'http://localhost:8081', changeOrigin: true, ws: false, timeout: 120000 },
+      '^/oauth2/callback': { bypass: () => true }
+    }
   }
 })
