Open ktseo41 opened 2 years ago
OAuth is an open standard for authorization that allows a user to grant a third-party application access to their resources on another service without sharing their credentials. There are several different ways to implement OAuth, depending on the specific requirements of your application and the service you are using.
Here is a general overview of how you might implement OAuth with a client, server, and database:
The client initiates the OAuth flow by redirecting the user to the service's authorization endpoint.
The user interacts with the service to grant permission to the application to access their resources.
The service redirects the user back to the client with an authorization code.
The client sends the authorization code to the server, which sends it to the service's token endpoint.
The service returns an access token and a refresh token to the server.
The server stores the tokens in the database, associating them with the user's account. => 인증 이후, 발급받은 token을 이용해 유저 정보 api를 요구한다. 추가로 네이버에 요청할 건 없어서 이 과정은 필요 없어보인다.
The client uses the access token to make requests to the service on behalf of the user.
The server uses the refresh token to obtain a new access token when the original one expires. => 따라서 위 두 과정도 필요 없다. 대신,
인증이 완료되면 네이버에서 발급해준 unique_id 를 DB 유저 테이블에 저장한다. 동시에 access_token, refresh_token을 발급한다. refresh_token은 DB에 저장한다.
access_token이 만료되면 refresh_token이 DB에 있는지 확인한 후 둘 다 재발급한다.
This is just one way to implement OAuth, and different services might have different implementations or requirements, for example some services may use different grant types or have different endpoints.
It's important to consider the security measures, such as securing tokens and tokens on client side, handling token expiration and refresh, ensure there are no cross-site request forgery (CSRF) attacks,etc. Also, it's important to comply with the regulation and security standards, such as the GDPR, HIPAA.
사용자에 대한 인증은 네이버 로그인을 통한 인증으로 대체가 되었기 때문에 비밀번호에 대한 검증이 추가로 필요하지 않습니다. 사용자에 대한 조회가 완료되었을 경우 세션에 로그인 정보를 발행하거나 쿠키로 로그인 정보를 발행하여 로그인 상태로 만들 수 있습니다.
간단한 구조의 jwt 사용 예시 코드, 설명
// Handling post request
app.post("/login", async (req, res, next) => {
let { email, password } = req.body;
let existingUser;
try {
existingUser = await User.findOne({ email: email });
} catch {
const error = new Error("Error! Something went wrong.");
return next(error);
}
if (!existingUser || existingUser.password != password) {
const error = Error("Wrong details please check at once");
return next(error);
}
let token;
try {
//Creating jwt token
token = jwt.sign(
{ userId: existingUser.id, email: existingUser.email },
"secretkeyappearshere",
{ expiresIn: "1h" }
);
} catch (err) {
console.log(err);
const error = new Error("Error! Something went wrong.");
return next(error);
}
res
.status(200)
.json({
success: true,
data: {
userId: existingUser.id,
email: existingUser.email,
token: token,
},
});
});
app.get('/accessResource', (req, res)=>{
const token = req.headers.authorization.split(' ')[1];
//Authorization: 'Bearer TOKEN'
if(!token) {
res.status(200).json({success:false, message: "Error! Token was not provided."});
}
//Decoding the token
const decodedToken = jwt.verify(token,"secretkeyappearshere" );
res.status(200).json({success:true, data:{userId:decodedToken.userId,
email:decodedToken.email});
})
The answer to this question is refresh token rotation, refresh token reuse detection and deleting all old refresh tokens when a new one is generated. Let me try to explain my answer — when a new access token is generated (at the time of sign in/signup or using a refresh token) — a new refresh token should also be generated (this is called refresh token rotation), and all the previous refresh tokens must be deleted.
This is how I would go about it:
5 minute access token as JWT (self-contained, don't need to store it anywhere).
7 day refresh token for one-time usage: generate random secret (don't need to sign it/encrypt it), store it in Redis with a 7 day TTL (or MySQL with a valid_until timestamp). On /refresh_token validate the provided token (check if it's in Redis/MySQL) and delete it. Generate a new access and refresh token pair. (I like to rotate refresh tokens as well, it makes it a bit more secure: it's probably already rotated=invalid if stolen)
// ...
try {
let refreshToken = await RefreshToken.findOne({ token: requestToken });
if (!refreshToken) {
res.status(403).json({ message: "Refresh token is not in database!" });
return;
}
if (RefreshToken.verifyExpiration(refreshToken)) {
RefreshToken.findByIdAndRemove(refreshToken._id, { useFindAndModify: false }).exec();
res.status(403).json({
message: "Refresh token was expired. Please make a new signin request",
});
return;
}
let newAccessToken = jwt.sign({ id: refreshToken.user._id }, config.secret, {
expiresIn: config.jwtExpiration,
});
return res.status(200).json({
accessToken: newAccessToken,
refreshToken: refreshToken.token,
});
// ...
--- naver access_token, refresh_token은 이제 필요 없음
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNzQzMmM2YzAtOGFiMS0xMWU5LWE3MGUtMTk2NDkxNWI4NjdiIiwidG9rZW5faWQiOiI1NjRhMjcwYS04NTgwLTRhMzAtODExMS0zN2FjYTY3NWM3Y2MiLCJpYXQiOjE2NzM2NzgwMjYsImV4cCI6MTY3NjI3MDAyNiwiaXNzIjoidmVsb2cuaW8iLCJzdWIiOiJyZWZyZXNoX3Rva2VuIn0.d23fALYMp2ASm3q1gpW9duNxKDSb8H-3hcNZGhKQfHY
https://github.com/velopert/velog-server
By design, domain names must have at least two dots; otherwise the browser will consider them invalid. (See reference on http://curl.haxx.se/rfc/cookie_spec.html)
When working on localhost, the cookie domain must be omitted entirely. You should not set it to "" or NULL or FALSE instead of "localhost". It is not enough.
reply
.setCookie("accessToken", accessToken, {
path: "/",
httpOnly: true,
maxAge: 60 * 60 * 1000,
domain: "localhost"
})
// server
server.register(cors, {
origin: ["http://localhost:5173"],
credentials: true,
});
await fetch(`http://localhost:8080/auth?code=${code}`, {
credentials: "include",
});
server.register(cookie, {
secret: "cookie-secret",
hook: "onRequest",
});
The cookie will still be visible, but it has a signature, so it can detect if the client modified the cookie.
인증 과정 진행