My client asked me to develop a web api and use SAML as authentication.
I came across with the image below from this site, that shows the authentication flow.
However I don't know how to use the token that is generated after the authentication.
Do I need to store it as any other session variable?
Do I have to renew the token after a certain time or it lasts during all the session?
Note: The authorization server / idP is maintained by other party.
Since you develop the web API yourself, there's no need to refresh the token.
You're API needs to be added as relying party to the IdP. After that you can redirect to the IdP and initiate authentication. The token you get back contains several attributes (also configurable on the IdP) like unique user-id (uid), e-mail, name, country, etc...
In most cases this token is signed using a public/private key. Your API server needs to verify the signature, the issuer (the IdP), the audience (your API) of the token and consume the attributes. When everything is OK, you'll need to provision a local user account, link the external uid and create a local authentication cookie (or generate a OAuth2 token if your API uses OAUth2 or OpenIdConnect) for the locally provisioned user account.
Since this is a complex process, depending on the language/framework you're using, you might want to look into existing implementations.
Related
I am building an ASP.NET Core 6 Web API application for mobile clients (and maybe later SPA JS app). The application should have sign-in with Google option. I also want to add my own app's custom sign up and sign in options that would also be based on JWT authentication and not cookie.
I understand that for my custom sign in flow my app will generated JWT that will be sent to the client.
But I have few questions how that works when user signs-in with its Google account:
who's responsibility is to generate the JWT when user signs-in with its Google account? Is that responsibility of Google or mine application? I don't want Google to return JWT to the client in the cookie.
Then when client is authenticated with Google, and sends requests to my application, how can my application validate JWT token it gets?
When user signs in with Google for the first time, should I automatically register that user in my application (I am using Identity framework) by taking claim values (email) from the JWT? What is the general practice here?
I am trying to understand these processes and flows so sample code is not necessary (but I do welcome it).
Ad.1. Normally, in a larger system, you would have an authorization server (AS) that would handle user authentication and the issuance of tokens. Your clients would contact only the AS, and the AS will be able to provide the user with different forms of authentication: e.g., through your website's password or through Google. The AS is the single point of issuing tokens to your clients. It can issue tokens regardless of the authentication method used. So it then doesn't matter whether the user authenticated with Google or a password, the client will still get the same access token.
Ad.2. When the AS issues token to your client, then you don't have any problems validating that token. The client doesn't care if the user authenticated with Google or not, it's not relevant in this case.
If you decide to skip using an AS and let the client receive tokens directly from Google, then you can still verify them. An ID token is a JWT and can be easily validated with a JWT library using verification keys provided by Google. Access tokens returned by Google are opaque tokens (If I remember correctly), and you need to check whether Google exposes an endpoint to verify them.
Ad.3. That is the general practice. When the user authenticates with Google and you notice that you don't have that user's data in your system, then you take the information from Google's ID token and create a user entry in your system.
I am using identity server 4, I followed the tutorial, so I have an api, mvc client, console client, and js client.
I saw this blog too, which is probably close to what I need:
https://medium.com/all-technology-feeds/testing-your-asp-net-core-webapi-secured-with-identityserver4-in-postman-97eee976aa16
what I need is an api, where clients can access data, but first, they need authenticate.
we also have the console client, which is also close to what I need.
The only issue with this examples is that in both cases client knows the secret. But in our case multiple clients should use the same api, and if they all have the same secret, they can log in on behalf of each other, but I don't want to have different secrets.
So what I think I could do is to create an api which takes username and password, and returns the token. But I am not sure if this is the right way to do things? This feels like a resource owner flow, which is not supposed to be used for client facing APIs if I am correct. But in that case, how should I go it?
thanks
It seems that there is some confusion. Allow me to give a short summary. First the terminology:
A user is a human that is using a registered client to access resources.
A client is a piece of software that requests tokens from IdentityServer - either for authenticating a user (requesting an identity token) or for accessing a resource (requesting an access token). A client must be first registered with IdentityServer before it can request tokens.
Resources are something you want to protect with IdentityServer - either identity data of your users, or APIs.
Client credentials: The simplest grant type and is used for server to server communication - tokens are always requested on behalf of a client, not a user.
Now about authentication. The client requests tokens at the IdentityServer endpoint. When you use a client in combination with the client credentials flow, then you'll need a clientid + secret. Where secret is really secret and should be known to the client only. You can't use the same secret here. Seems logical when compared to users, they don't share the same password either.
This is close to the resource owner flow, however a client cannot login as a user. For that you'll need another flow, like the hybrid flow. In that case the client logs in on behalf of the user. The difference is the presence of the "sub" claim (the id of the user) in the token.
The client in this case is your app: console or mvc. The first only supports client credentials where the secret is mandatory, the second supports a hybrid flow, where secret may be omitted:
In certain situations, clients need to authenticate with
identityserver, e.g.
confidential applications (aka clients) requesting tokens at the token endpoint
APIs validating reference tokens at the introspection endpoint
The Api is your resource, that you want to protect. The Api never authenticates a user or client. This is done by IdentityServer. It only verifies the token (using the IdentityServer4.AccessTokenValidation package). For that it has its own secret that should only be known to the Api.
In order to grant the client access to the resource you'll need to add the scope to the client in the configuration of IdentityServer. The client is then allowed, not required, to request a token that grants access to the resource.
Again, the Api has nothing to do with authentication. It is also not bound to one client. Multiple clients can access the resource. All you have to do is add the scope to each client that should have access to the resource.
So there is really nothing against it that clients and resources know their secret. You don't have to change anything. All you have to do is choose the appropriate flow.
I have an API Server (Resource server) and multiple apps, Web GUI (SPA) and a Desktop client and maybe more coming.
I'd like to use openid-connect besides http basic authentication for my API Server.
It should be configurable which openid provider to use. My own, facebook, google...
I only want to do authentication, I do not need their API. I only need some profile data like email or firstname.
Let's say I have configured google as my IdP and I'm currently using my Web GUI (SPA). I need to login, no problem, according to https://developers.google.com/identity/protocols/OpenIDConnect I redirect the user to google, get my authorization code and the Web Gui (SPA) gets an id_token and access_token from google.
No problem so far, but now the SPA has to work with my API Server and the API Server needs to authenticate every request (since it is a stateless rest api) coming from the Client (WebGui SPA) and needs to know which user actually did this.
A
So the access_token from google is meant to be used to access google api's right? But I also could just pass this access_token with every request to my api server and the api server calls https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=xxx to verify the access_token and get the account name (mail). But this doesn't sound right, does it?
B
I also have and id_token which I can verify without calling google server everytime. So could I also just pass the id_token as bearer with every request to my api server and the api server can verify the id_token? But according to openid-connect spec the access_token is actually the one which just get passed to the api server and the id_token must stay on the client.
But then the id_token would be completely useless to me, the API server needs to know who the user is, the client (Web GUI) doesn't really care.
C
Or since it is my own API Server, does my API Server actually needs to implement the whole oauth2 system by itself, just not authentication but creating access_token and more. So I would have a /api/tokensign to which I can pass the id_token from google, the API verifies the id_token and creates an access_token for my WebGUI (SPA). And this new access_token can be passed as bearer to every api request. This actually sounds as the best solution according to specs, but do I really need to implement oauth2 by myself into my API? Sounds like a heavy addition since A and B could also be implemented.
My rest-api needs authentication with every request so is A, B, C the right approach? Please don't tell me this is opinion based, it is not.
What is the right way using oauth2/openid-connect for authentication?
You can use all three methods you have mentioned above, but indeed with some considerations. I will explain them with regards to available specifications.
Scenario - Two systems S1, S2
S1 - Identity provider
S2 - API endpoint
What you need - Trust and use 'Tokens' issued by S1 to access S2
Explanations for proposed solutioins A, B and C
A - Verify tokens issued by S1 for each call
This can be done using the RFC7662 - OAuth 2.0 Token Introspection endpoint. This validation is valid by the specification so yes you can use the token verification endpoint.
Advantage for this method is that, if a token is revoked, the effect is instantaneous. The very next API call will fail. But indeed there's the implication on performance. You need an extra verification service call.
Note that you do not need to get the account name from this verification response. It could be taken from ID token and could be used to verify for extra protection.
B - Trust tokens issued by S1 for each call
Now this approach is something extended from RFC6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage. You can indeed use ID toke to authenticate and authorise an end user. This link contains a good explanation on the ID token usage as a bearer token.
You can indeed verify the validity of token using MAC and even encryption. But be mindful to use short lived tokens and to always use TLS. And be mindful about refreshing tokens.! Because according to openID connect specification, ID token is not a mandatory item for a refresh token request.
C - A wrapper for federation
For this you can write your own solution or use an existing solutions (ex:- WSO2 identity server). This identity server will configured to choose the identity provider on your application (client like desktop app or web app). Identity server will do the necessary redirects and provide you the required tokens. But indeed you will need to use introspection endpoint to validate the token validity.
If you go one step ahead of this solution, you can try to implement a code exchange mechanism. You can exchange the token carry from external to tokens issued internally by one of your system (ex:- Google access token to your internal access token). The advantage of this approach is you have control over validation. Also since subsequent token validations are done internally, there should be a performance improvement.
Hope this explains some doubts you have.
The model for our product is like this:
Api backend (headless)
I already have oauth set up and ready to use with a resource owner credentials grant. Anyone who wants to use our api can do so using either an API key or their username/password. Of course they also need their client ID and secret.
SPA frontend that accesses the Api
I have built an SPA that will uses the api to provide a portal GUI for our clients. Given that this client-side app is owned and administrated by us (so it's a trusted app) how can I safely authenticate users using only username/password with oauth?
Originally it was using a JWT auth system that only required username/pass but now that we've implemented oauth I'd like to consolidate. It's unreasonable to make every user need to also have their client id and secret on hand to login, but I want users to have full access to the api from the GUI.
I've looking at using CSRF tokens but how would that work with my app when nothing is generated server-side?
I'm not sure how to proceed.
EDIT: very similar to the problem here.
I have decided to use the solution described here.
And here is a snippet of my implementation
The TL;DR version is
Create a proxy between the app and the api
Store the client ID and secret in the proxy
App logs in using password grant type -- proxy intercepts login request and inserts client id and secret
On login response proxy returns access token as an encrypted cookie
Client stores cookie and sends with api requests (to proxy)
Proxy decrypts cookie and inserts access token into Authorization header before forwarding to api endpoint
For me this has several advantages over implementing something custom on the api itself:
No need for custom grant on oauth server
ID/secret is hidden from app securely and can still use password grant
oauth server can identify client (no need for separate client ids for each user)
You should not use the resource owner credential grant from a JavaScript application. The fact that you own and administer the application does not make it a trusted application.
A trusted client is an application that can keep a secret. SPAs or any JavaScript app cannot keep a secret.
You should use the implicit grant for non-trusted clients.
I did some investigation about restful api authentication. Most people pointed to Oauth2 for restful api authentication. I looked into some of resouces, especially this link https://developers.google.com/accounts/docs/OAuth2.
It seems to me Oauth2 is for a third party app to access users' data in google/facebook(or other data provider).
Our problem is that we own the data, we don't need to access our client's any third party data and our clients don't have to any third party data. We want to protect our api with some sort of authentication.
For our case what is the convenient technologies for our restful api authentication ? We will expose our api like this
https://ourdomain.com/api/<endpoint>
Our clients can access a website first to register https://ourdomain.com and they should be able to get clientId and clientKey from our website for accessing apis. Our clients should be able to consume through some sort of authentication
In oAuth 2.0, there are several types of grant types. A grant type is just a way to exchange some sort of credentials for an access token. Typically oAuth refers to 3rd party usage with a Authorization Code Grant. This means redirecting the user to the resource owner's website for authentication, which will return back an Authorization Code.
This clearly doesn't make sense for 1st party oAuth use, since you ARE the resource owner. oAuth 2.0 has considered this and included the Resource Owner Password Credentials Grant for this purpose. In this case, you can exchange a username and password for an access token at the first party level.
See https://www.rfc-editor.org/rfc/rfc6749#section-4.3 for more details.
If I understand correctly, what you need it similar to OAuth in a way that you do the exact same thing minus granting a 3rd party app access to a user's resources.
In OAuth, there is a central system that manages authentication and authorization by checking an app's credentials + user's credentials and dishing out authorization tokens. There are multiple endpoints that will accept these authorization tokens.
The tokens are basically encrypted strings that contain info about the user's credentials and some other info that might be needed by your app.
What you need (i believe) is a similar authentication endpoint, that the client hits with its credentials and gets a token.
So,
i) Create a registration form/console where a client can register and get his credentials. Have a look at this.
ii) Define a HTTP endpoint where the user exchanges his credentials for an access token + refresh token.
iii) The client can hit the resource endpoint with the access tokens to make authenticated calls to any of your endpoint.
iv) At the back-end you'd need a common service that verifies the tokens and extracts info from it.
PS - This is just a minimal system, there would be a lot of security considerations like what if some unauthorized app gets access to some client's access tokens.
You can find much information about CSRF attacks, noonces, timestamps and other methods of mitigating security concerns.
Just to be clear with the original question:
OAuth2 needs at least a client and a server
OP was wondering how to secure a REST API, and why everyone is talking about third party authentication providers (Google, Facebook, ...)
There are 2 different needs here:
1 - Being able to secure a personal API (ourdomain.com)
Client Server
Consumers <----> Your API
2 - Being able to consume a public API (For example getting a user's Google contact list)
Client Server
You <----> Google APIs
OP actually needs the 1st: implement an OAuth2 server in front of its own API.
There are many existing implementations for all languages/frameworks on Github
Finally, here is one nice Oauth2 technical explanation, and I'm shamelessly taking one of its schemas here:
No I'm not working at Google, I'm just taking Google as a public API supplier example.