I'm looking for recommendations on how to approach a next.js front end that uses Apollo and GraphQL to access a PostgreSQL database. I figured it made sense to separate the front and back end, but I'm realizing there are tradeoffs. Next.js and NextAuth.js seem designed to work well when using the Next.js API functionality.
A few requirements:
Data needs to be restricted based on the user (public, internal, admin).
Using Google OAuth for signing in
With this in mind, NextAuth.js gets more complicated if you want the back end to be aware of the user's access rights.
However, if my apollo/graphql back end is independent there are definite benefits like:
I can swap out the front end if ever needed so there's some flexibility
Code and dependencies may be simpler than a combined front/back end
My current challenge is that I've got NextAuth.js working within the Next.js app, but I haven't figured out how to control data access. The best idea I've got so far is some sort of token management that mixes NextAuth.js and my back end. That doesn't seem to be the way NextAuth.js is designed though so I'm rethinking the whole architecture and looking for suggestions.
Thanks!
I found a very brief discussion of a similar question here, but I'd love to hear how others would approach this.
How to forward user sessions in Next.js + Graphql decoupled architecture?
I'm going to do my best to give a fairly generic answer, using a JWT for Authorization, but I'm going to have to make some assumptions since I'm not super familiar with Google OAuth & related Google system.
First, and most importantly, it's important to clarify the difference between Authentication, or "who you are" and Authorization, or "what you can do."
The best idea I've got so far is some sort of token management that mixes NextAuth.js and my back end. That doesn't seem to be the way NextAuth.js is designed though so I'm rethinking the whole architecture and looking for suggestions.
NextAuth is an Authentication library, and doesn't support external validation of the NextAuth-created JWTs, so you're right to not want to mix NextAuth with your backend. When someone logs in NextAuth creates a NextAuth-specific JWT (an ID Token) that will be passed between the Client and the Next Server. It tells you who the user is, and proves that they've logged in. Unless you're using database sessions, which I haven't used so can't speak to.
Extra work is required to implement Authorization so that you have a JWT that also describes what access rights the user has, that you can pass to your backend.
Ideally you will be able to leverage Google OAuth for this, and assuming that is the case, this is what I would do:
For the architecture
I'm not very familiar with GraphQL/Apollo, but separation there seems fine. Important to note, though, that not separating is also probably fine. Any approach will have tradeoffs, so you'll have to evaluate what works best for your situation.
Whenever you make a call to the backend, you pass your JWT with the call as an Authorization header, in the form of Bearer <token>.
On the backend, then, you validate the token with each incoming call, and allow the call to proceed (or not) as appropriate.
This is the relevant info I found in the Apollo docs.
For the token
In your NextAuth provider configuration, in the jwt callback you can add information to the NextAuth JWT.
Ideally, your Google OAuth also provides you a JWT (an Access Token). This should be something that should be relatively easy to validate on the backend, and it is what you'd want to use for Authorization.
You can store this Google OAuth JWT (access token) within the NextAuth JWT (id token) when the user first logs in, and then retrieve it on the Next.js server before you make your calls to the GraphQL backend. That would look something like this:
// [...nextauth].js
const options = {
// ... other configuration
callbacks: {
jwt: async (token, user, account, profile, isNewUser) => {
const isSignIn = !!user
if (isSignIn) {
token.b2c = {
accessToken: account.accessToken,
refreshToken: account.refreshToken,
iat: profile.iat,
exp: profile.exp,
}
}
return Promise.resolve(token)
}
}
}
This is a simplified example from the configuration I use. My config is for Azure AD B2C but it's the same general flow you're looking for. You can see my full config here which shows some additional code I use to handle refreshing the access token as needed.
If you don't have something usable from the Google OAuth flow, this gets more complicated and you'd have to build something custom.
Related
Actually I have an API called update user data, it is called when the user moves from one page to another page. If the user copy the API from console and post in postman, user should not able to update the user data. How to provide security or implement feature to not to update data through post man.
You really can't.
You can slightly make it harder using some CSRF protection, but that's just it - it will only make it a bit harder, but not stop anyone determined.
If your API is public, you should be ready for your users to have custom client apps.
I am a bit confused by your question. Because PostMan or other applications like Fiddler are created to make the job easier for developers during development. anyhow if you are concern about who makes call to your webpage, you can make your API private and just give access to the user that have the right credentials. You can also read about CSRF or XSS.
My task is to implement a resource server(RS) for IdentityServer4(IS4). The RS should fetch data from a database and send the necessary information as a json object back to the caller (client). This is needed because we have to return complex objects.
I already setup IS4 succesfully and its already running in Docker for testing purpose. I also setup the needed database.
My understanding of the flow would be, the user requests data from the RS sending the access-token, the RS then validates the token, checking if the caller is allowed to access the api using the IS4, if everything is okay the RS returns the data to the caller.
My problem is, as I'm new to this subject, how would I implement a RS? Do I create an API which is added as a scope to the user? Or is there a RS already implemented in IS4?
So yes you'll need to write your own API to serve your own resources, IdentityServer will only manage your identities for you (as well as handling external logins if that's what you need). I'd recommend going to the IdentityServer docs and working through the quick starts in order as shown below:
This will give you a good start but you'll then need to go away and research APIs more generally, there's a tonne of good info online about building (RESTful) APIs. You may find it useful to sign up to something like PluralSight and work through a couple of their courses, they're often very good.
One other thing to bear in mind is that IdentityServer is for identity, in other words Authentication and not specifically for Authorisation so you may need to add something for this. You can of course use a users identity for authorisation purposes but in most cases you'll probably need to augment the info you store about their identity to authorise them for access. See this link for more info around this topic.
I started to integrate GitHub3.py, and from what I have seen it appears to be an excellent library for my use.
However, I'm a little confused on how to go forward and get using the library in my Django project. So far, I have implemented a login method using the GitHub web flow API, this returns me a code which I could send to the API to return an OAuth token.
However, from reading the GitHub3.py docs, I'm not sure how this can be done.
So I'm wondering how I should go forward from here. I have read this past issue https://github.com/sigmavirus24/github3.py/issues/7 - I don't believe this applies to me since an OAuth code has a already been achieved.
I'm fairly new to Python and OAuth authentication, so I would appreciate it if somebody could push me in the right direction (if the library has code to OAuth methods or if there is another way that I am not familiar with)
Thanks!
So if I understand you correctly you have a token for a user who has granted you permission (i.e., they logged went through the webflow and your application has received and stored the token GitHub returns).
In this case you can do the following:
import github3
g = github3.login(token=TOKEN_RECEIVED_FROM_THE_API)
With that (and assuming you have the proper scopes on the token) you should be able to use most methods that require authentication. If you have the user scope you can use g.user() to get some extra detail about the logged in user.
If you have repos then you can also list a user's private repositories.
In short, when we wrote the library we wanted to make it easy to authenticate in a number of ways and then use the same API that you would if you had authenticated another way.
We intend to develop rest based api. I explored the topic but it seems, you can secure api when your client is an app (So there are many ways, public key - private key etc). What about websites / mobile website, if we are accessing rest based api in website which do not use any login for accessing contents ( login would be optional ) then how could we restrict other people from accessing rest based api ?
Does it make sense using Oauth2.0 ? I don't have clear idea of that.
More clear question could be ,How can we secure get or post request exposed over web for the website which doesn't use any login ?
If it's simple get request or post request , which will return you json data on specific input, now i have mobile website , who will access those data using get request or post request to fetch data. Well, some else can also access it , problem is i am not using Login, user can access data directly. But how can we restrict other people from accessing that data.
What do you think is the difference between securing a website that is not using REST vs one that is using REST API?
OAuth provides authorisation capabilities for your site, in a REST architecture this means a user of the mobile application will have to provide their credentials before being allowed to access the resource. The application can then decide on if that user has access to the requested resource. However you've said your website doesn't need use authorisation.
You can use certificates however good luck managing the certificate for each client. My take on it is for your explanation you don't need to secure your website because you will never be able to manage a trust relationship between the client and the server. There are some options though:
You build your own client application that you ship out to people which can verify itself with the server using a packaged certificate with the client. E.g. iOS has this kind of feature if you build for that device.
You provide a capability to download a certificate that is 'installed' in the browser and used when communicating to your REST API
Use something like a handshaking protocol so when a client wants to make the first request it says; 'hi I'm a client can we chat?' And the server responds with 'yes for the next X minutes we can however make sure you send me this key everytime you tell me something YYYYYY' (you can use something like SecureUDID or equivalent for other devices than iOS).
There are probably others but you get the basic idea. Again in my opinion if your resource doesn't need authorisation then you don't need to secure that REST API. Can I ask what kind of data are you exposing via this REST API or functionality your providing? That might help provide a better answer.
You want authorization: only some agents (mobile clients) and/or users should be allowed to access those APIs.
To solve that problem, you need identification: a way for the server to tell who is who (or what), so the right decision can be made.
There are many different way to provide some form of identification, depending how much you care about security.
The simplest is a user agent string, specific to your mobile clients. But it can be faked easily. Slightly harder to fake are client based 'secrets' - embed some kind of secret or key in your mobile client code. You can make it really complicated and secret, but as ramsinb pointed out, you can't get security this way as it would require you to be able to guarantee that the secret you're shipping with the client (wether it's code, algorithm or any other fancy construct) can't be compromised or reverse engineered. Not happening when you don't control the client.
From there, 3 choices:
Security isn't really required, don't bother
Security isn't really required, but you still want to limit access to your API to either legit users/agents or people ready to invest some time hacking your protection - go with a specific user agent or a client embedded secret - don't invest much into it as it won't block people who really want access to get it anyway
Security IS required - and then I don't think there is a way around authentication, wether it's login/password, user specific (device specific?) keys, OpenID, etc... No matter what, you'll have to add to the user burden to some extent, although you can limit that burden by allowing authentication to persist (cookies, storage....)
I'm trying to implement SSO using Atlassian Crowd, and there's a surprising lack of good documentation or even examples out there.
So far, I authenticate a user using CrowdClient.authenticateSSOUser, and get back a SSO Token (String) if successful. Then, I take this token and stuff it in the cookies myself (via HttpServletResponse). On subsequent page visits, I grab all the cookies, search for this one, and then call the CrowdClient.validateSSOAuthentication method on it.
My question is this: Am I supposed to be using more Crowd code for SSO? I seem to be doing more manually than I'd expect.
...I DO see hints of other possibilities out there... For example:
In crowd.properties, you can specify a crowd.token_key, which is apparently what name the app should use store the token in a cookie (though setting this value doesn't magically make that happen).
Things like the CrowdHttpTokenHelper exist in the latest version - yet seem to have no easily-found related examples (or documentation other than JavaDoc).
Yes, there are possibilities out there that will hopefully help or at least serve as reference.
For a readily available implementation, you might want to look into Integrating Crowd with Spring Security.
If you need finer control, use a CrowdHttpAuthenticator. It will allow you to authenticate a request with a username and password as well as check if a session has an existing session cookie. (Its concrete implementation will accept properties and uses crowd.token_key.)
CrowdClient is available if these don't fit your needs, but it's not the only option.