I'm building an app where I need to authorize the users based on 'mode' queryParameter & apikey that comes from the consuming applications.
It will then send an api request to backend and confirm if the user has the authorization. Also want to ensure that apikey is not exposed to outside.
Just wondering how am I going to approach this in Next.js?
I was thinking to build a local api and fetch the backend response and then call the local api from the pages. Because this has to happen in the _app.js (centralized), where getServerSideProps is not permitted, I'm bit confused on my approch.
Really appreciate your feedback
Next.js is used to build client-side app. General rule of thumb for client-side authentication is "don't authenticate / authorize on client-side".
Applications must place authorization outside client-side code, since it could be arbitrarily modified by any party
source : https://www.staticapps.org/articles/authentication-and-authorization/
So, centralized authentication is out of Next.js scope. It's in the scope of microservices (following Jamstack architecture https://jamstack.org/).
Related
Here's my setup. I have a NodeJS express server providing endpoints and hosting my frontend which I've built using React. I have the Spotify client id & secret stored in a .env file which the frontend references, and therefore publicly exposes.
Currently, for users to link with Spotify, the frontend can redirect to Spotify's authorize page and pass the client id and secret (and a redirect uri) in the url params. They then log in with their Spotify credentials and accept my app's terms. Then Spotify then redirects them to the provided redirect uri, which is just another page of my React app. The user's refresh token is passed as a url param for my frontend to receive. It then sends refresh token to my server using one of my endpoints and I store it in my database under their account.
This works fine, except for the fact that my app's client id and secret are publicly exposed through my frontend. I'm trying to work out a way to allow users to link with Spotify without having the frontend know this information, because if it leaks then people can make calls to Spotify's API on my behalf. But I can't seem to get around the fact that the client's browser needs to at some point have access to something like this.
const url =
'https://accounts.spotify.com/authorize?' +
querystring.stringify({
response_type: 'code',
client_id: spotify_client_id,
scope: spotify_scope,
redirect_uri: spotify_redirect_uri
})
window.location.href = url
I'm new to web development so there may be something obvious I'm neglecting. If anyone has any ideas, I'm all ears. Thanks in advance!
In this particular scenario, you’ve designed around the entirely wrong OAuth flow for the job. Client credentials-style authentication/authorization is not intended to be used in the manner you describe, for the reasons you describe. Instead, you should be using the offered authorization code with PKCE flow, which provides similar functionality for web apps, etc. without necessitating the exposure of your sensitive authentication secrets.
Spotify is pretty explicit about this in their documentation (emphasis mine):
Which OAuth flow should I use?
Choosing one flow over the rest depends on the application you are
building:
If you are developing a long-running application (e.g. web app running on the server) in which the user grants permission only once,
and the client secret can be safely stored, then the authorization
code flow is the recommended choice.
In scenarios where storing the client secret is not safe (e.g. desktop, mobile apps or JavaScript web apps running in the browser),
you can use the authorization code with PKCE, as it provides
protection against attacks where the authorization code may be
intercepted.
For some applications running on the backend, such as CLIs or daemons, the system authenticates and authorizes the app rather than a
user. For these scenarios, Client credentials is the typical choice.
This flow does not include user authorization, so only endpoints that
do not request user information (e.g. user profile data) can be
accessed.
The implicit grant has some important downsides: it returns the token
in the URL instead of a trusted channel, and does not support refresh
token. Thus, we don’t recommend using this flow.
It may go without saying, but since you’ve already elected to publicly publish your app secret, you should consider it compromised and invalidate it immediately before malicious actors are able to indeed use it to craft abusive API requests.
We have an application that has frontend UI(Which is a web application) which communicates with a resource server. Our frontend will be using some APIs from a resource server to get data.
I am planning to add frontend to Okta and provide access to okta registered users.
In the resource server, we have some APIs that we want to expose to our customers to integrate in their system(Programmatically). To use our APIs, we have to provide client credentials(client ID/secret) to them. Using clientId/Secret, they will get access_token and will use that in a subsequent request. We can display this clientId/Secret via frontend UI once the user logs in to it via Okta.
How should I authenticate requests to the resource server from the frontend? And how do I authenticate requests to resource server via customer using clientId/Secret? Should I use one or two different tokens for this purpose?
Does Okta provides per-user client Id/secret that user(customer) can use to get access_token and send it to access resource server and resource server validate token against Okta.
I just did something very similar. You can read about my experience here: How to pass/verify Open ID token between .net core web app and web api?
I don't know what application framework you are using (.net, node, etc), but if you're using .NET the steps are to (a) install the middleware in your web app, (b) install the middleware in your api app, and (c) make sure calls from your web app to the api app pass the id_token.
If you, in addition to that, need to secure it for external users - it should work the same way. The only difference is they will manually call the /authorize endpoint to get their token - but the middleware should take care of the token verification for you in both cases.
Note I did experience one odd thing which is that I needed to pass the id_token and not the access_token. It is also worth mentioning that the claims were interpreted differently in the app and the api (in that the name of the claims for say, userid, were different between them - the data was still the same).
You will have to use 2 different access tokens. There are 2 different flows going on here:
Web UI to API
Business partner system to API
Technically this means:
Authorization Code Flow (PKCE)
Client Credentials Flow
And in terms of tokens it means:
In the first case there is an end user represented in access tokens (the 'sub' claim)
In the second case there is only a Client Id claim in access tokens
I can advise on token validation techniques if needed - let me know.
To me though this feels like an architectural question - in particular around applying authorization after identifying the caller and versioning / upgrades.
Based on my experience I tend to prefer the following architecture these days, based on 2 levels of APIs: eg with these ones exposed to the internet:
User Experience API serves the UI
Partner API deals with B2B
And both entry point APIs call the same core services which are internal. Might be worth discussing with your stakeholders ..
If i host my Identityserver4 and the Api in the same Asp.net Application.
What will be used for authentication for the API Controllers?
The Cookie from Identityserver or the token which i get from the oidc-client in my SPA application?
I my tests i can access the API, also if i didn't send the token within the angular http reqeuest as long as i have the Cookie...
But is this a correct and save way???
The MVC Controllers for Identityserver are protected with ValidateAntiforgeryKey, but not the API Controllers.
Does it make sense to host both in the same Application???
Edit:
In Details, the API is used for managing the IdentityServer.
CRUD Operations for Clients, Users, Resources,...
For example:
The IdentityServer is reachable at http://localhost:5000
I want build an Angular2 SPA Admin UI which is available at http://localhost:5000/admin
The reason for mentioning ValidateAntiforgeryKey is, because if i only use Cookie Authentication for the CRUD API i should also protect these API'S with ValidateAntiforgerKey, or?
It sounds like your API and Identity Server are two separate concerns and should be handled as two separate apps. This makes it a lot easier to maintain.
You need to set up an ApiResource and a Client where you add the ApiResource as an AllowedScope in your Identity Server configuration.
Then in your API app, you must add add the authentication middleware UseIdentityServerAuthentication.
The details are explained here:
http://docs.identityserver.io/en/latest/topics/apis.html
I can see you are mentioning ValidateAntiforgeryKey. This attribute is not used for protecting against unauthorized users, but to make sure form data is being posted from legitimate forms.
Authentication is a bit over the top for me.
My understanding is:
Client performs the login
API or authentication server responds with a token
Client calls API (includes a header which holds the token)
API checks if the token is valid and if valid responds with a resource
I checked several options:
IdentityServer4
Has the advantage to easily implement 3rd party authentication like Facebook. You can easily use the ASP.NET Core identities to authorize your API based on roles.
Custom (simple) JWT authentication
Reference: ASP.NET Core Token Authentication Guide
With this approach, you have to make your own identity user and fetch it from a database.
Cookie authentication
The client holds the token in a cookie when sending a request you have to send it too.
My front-end is written in JS and back-end is ASP.NET Core, so it's CORS.
I don't know what should I use and why? Why do many recommend to use IdentityServer4; isn't the simple custom authentication enough?
(I have problems with the IdentityUser properties and the "hidden" database checks)
The problem with authentication is that it may be simple to write a few lines of code that accomplish the end goal of authenticating your users, but it's really complex to do so in a way that you won't regret it later; aka my application got owned.
One of the steps to take to try to prevent that from happening is don't try to reinvent the wheel and stick to using current standards. However, even with standards, you need to implement them accordingly and that is why you probably see recommendations like the one you mentioned. I would actually make the same type of recommendation my self, delegate as much as you can to third-party libraries like IdentityServer4 or cloud services like Auth0. (you should know I work at Auth0, so you can consider me biased; however, for a non-biased recommendation you can check ThoughtWorks Technology Radar).
Also, if you store tokens in cookies, although the storage and transmission of the token happen differently this is still a token based-authentication system; for more on the possible implications of choosing a client-side token storage approach check where to save a JWT in a browser-based application.
In relation to CORS, you did not make that explicit, so I thought it may be worthwhile to mention it. You only need to actually worry about CORS if you deploy your front-end and back-end in separate domains because even if development happens in isolation if they share a domain CORS is one less thing you need to worry about.
Conclusion
For a front-end browser-based application talking with a REST API, the most common approach is to go with token-based authentication that relies on OAuth 2.0 protocol to perform the actual issuance of the tokens. Additionally, you should aim to delegate token issuance to a third-party (IdentityServer4 or other) so that you don't need to implement or maintain that part of the system and only need to consume/validate the generated tokens.
I am struggling with understanding how to implement the following in Web API 2's OWIN pipeline.
I am building an application that will allow users to log in with several third-party identity providers such as Facebook, Twitter, LinkedIn, etc. However, I want the authentication step to be performed entirely client-side. For example, Facebook provides developers a snippet of markup and JavaScript that perform the authentication within the browser, resulting in a Facebook access token--all without any calls to my API.
The Web API templates that ship with Visual Studio 2013 all seem to assume that the API itself is in charge of the authentication flow. I have successfully gotten this style of authentication working, but in my opinion it is not the responsibility of the API to perform this work.
Here is the approach I have been trying to implement (so far unsuccessfully):
Provide endpoints like /authenticate/facebook that accept the appropriate access token and return a JWT with "decoded" claims if the access token is valid. This JWT would have similar claims regardless of the third-party identity provider. For Facebook, I think this involves a call to Graph API's /me endpoint.
Store the JWT in the browser's localStorage for subsequent API calls
Send the JWT in the Authorize header for each API call
Avoid cookies if at all possible
My questions:
Is this an appropriate way to handle third-party authorization?
Should the JWT's expiration match the third-party access token's? I assume yes, but I want to be aware of any caveats here.
Where and how do I store the third-party access tokens for use on subsequent API calls? Do I include them with the JWT?
Is there a template I can use out-of-the-box, or perhaps an online resource that implements authentication and authorization in this way? I don't understand how to use Web API's many classes and features to implement this.
I have this mostly figured out now. I believe my architecture choice is the correct one after much research, specifically into the so-called "assertion flow." I am using Thinktecture's Identity Server 3 project to act as my STS. I am using a custom implementation of ICustomGrantValidator to perform the validation of the Facebook access token and conversion to claims.