Since local storage and session storage are both accessible via JavaScript it is best not to store the authentication JWT in either of them to avoid XSS attacks.
Since OpenID connect 2.0 is performed on a separate domain how do we set a server-side HTTP only cookie that contains the authenticated JWT?
My guess is this:
The user goes to your website then clicks sign-in.
The user gets redirected to the 3rd party OpenID connect 2.0 provider.
The user signs in and is now redirected to the route of your choice www.example.com/myredirectlogin.
The user's browser then makes a get request when the redirect lands on my route and it passes in the JWT token in the URI.
The server then validates the JWT via Asymmetric algorithm with the public key given by the provider.
The server then returns a server-side HTTP only cookie with the JWT as the value and the client-side doesn't have any recollection of the JWT since it was only in the URI and isn't stored anywhere else.
My question is: Is the above the correct process to securely handle OpenIDConnect 2.0 flow?
I'm assuming you mean the "Id Token" when you say "authentication JWT", since that's the only JWT required by OpenID connect.
All the flows that OpenID connect supports are listed in the spec. If you want to log in to the authorization server and authenticate to a separate site, then you will often use the "authorization code" flow which doesn't send the ID token to the browser at all. There are other flows defined by OpenID connect, but none of them mention storing the ID token in a cookie - how the session is maintained between the client (the site you're authenticating to) and the browser is a separate issue from authenticating the user.
I found the answer within authorization code flow: https://connect2id.com/learn/openid-connect
List of steps
OAuth 2.0 and OIDC Authorization code flow
The user hits your website's login route
The user is redirected to an identity provider with a proper tenant id
The user is authenticated and is redirected to your callback route with an access token in a query parameter i.e. &access_code=234234sdfkljsak.
a get request is executed on your web server at the callback route with the access token in the query parameters.
this callback get route should then make a post-call to retrieve an actual JWTidentity token from the provider i.e. azure b2c and it will add the access token as part of the request either as a query parameter or post of body.
the provider (Azure B2C) then will respond with an identity JWT token that we will send back to the user's browser as an HTTP-only session cookie that way the user is now SSOed among all browser tabs and the cookie will be sent with every request automatically and is protected from xss.
Related
Context:
1 spa
1 api
1 existing passport strategy with jwt
Feature:
Connect additional account with oauth to the existing account
I already have an authentification using passport on nodejs.
This generates a jwt allowing the users to authenticate them with a bearer token in the header of each request to the api.
I would like to add an additional oauth connection to the existing account (actually it is docusign but I think the problem could be the same with other connections).
When there is the redirection with the authorization code, I cannot identify the user which has initiated the connection because I don't have the bearer token in the request header anymore and the data between the two accounts can be different (different emails for example).
Is there a workaround for this or did I miss something?
Thank you for your help
Passport has an Authorize method which can be used to authenticate with a secondary IdP. For example:
Use Passport#Login to enable the user to login to your application's primary IdP
Use Passport#Authorize to enable the user to authenticate with a secondary IdP (such as DocuSign) as needed.
Regarding state for your redirect method (determining which IdP should be used to exchange the authorization code for an access token):
You can use the state parameter that is sent as part of the OAuth authorization code grant flow. But be sure to also use the parameter as a random nonce to guard against a CSRF attack. Eg, send idp1|random_nonce so you can both check the nonce and know that you should communicate with idp1, not idp2.
You can use your application's session machinery to maintain your app's state knowledge of which IdP you're working with at the time.
The only one I can think of is having 2 apps. Each can run on a different port or vd. Each would have their own passport strategy. The two apps can redirect to eachother and/or communicate using API endpoints to pass data between them.
I am using Open ID Connect and requesting tokens from Azure Active Directory. I am using the authorization code flow, so I am receiving both the id_token and the access_token. I am using .NET Core.
My configuration of Open Id Connect is as follows:
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
Notice the Save Tokens set to true
When the user is logged in, I am able to retrieve both the tokens as follows:
string accessToken = await HttpContext.GetTokenAsync("access_token");
string idToken = await HttpContext.GetTokenAsync("id_token");
My question is, where these tokens are actually being saved, and how can I configure how these tokens are being saved?
I also heard that in the authorization code flow, the identity provider will return the authorization code, and the server would then use that code to request the tokens. However, I am not doing any of that programmatically and I am still able to retrieve the tokens. Is this something handled automatically with Open Id Connect?
Where these tokens are actually being saved?
As the OpenID Connect protocol diagram architecture describe, When a new session is started, a new cookie is returned to control this session. This "sesion cookie" is created based on "ID Token" and as long as this cookie is valid, user will be considered as authenticated. As you are using, OpenID Connect (OIDC), it create the cookie and save token there. you could refer this docs
How can I configure how these tokens?
If you want to configure your token mechanism Microsoft provides library fro that. You can use ADAL or MSAL for your own configuration.
Is this something handled automatically with Open Id Connect?
Thought its has some background mechanism but you have to use authentication library to handle on your application code. You could refer official docs
For more details you could refer flowing docs
Authentication implementation
Authentication Libraries
Code sample
response_type is set to code indicating that you are using the Authorization Code Flow.
When you use OIDC auth code flow along with clientid and clientsecret to get token, the work process is as below:
1.The user clicks Login within the regular web application.
2.Auth0's SDK redirects the user to the Auth0 Authorization Server (/authorize endpoint).
3.Your Auth0 Authorization Server redirects the user to the login and authorization prompt.
4.The user authenticates using one of the configured login options and may see a consent page listing the permissions Auth0 will give to the regular web application.
5.Your Auth0 Authorization Server redirects the user back to the application with an authorization code.
6.Auth0's SDK sends this code to the Auth0 Authorization Server (/oauth/token endpoint) along with the application's Client ID and Client Secret.
7.Your Auth0 Authorization Server verifies the code, Client ID, and Client Secret.
8.Your Auth0 Authorization Server responds with an ID Token and Access Token (and optionally, a Refresh Token).
I am trying to use openid connect to create a SSO for my application.
Basically we have one API layer and different Apps (clients) will consume the service of this layer.
To start with we added OAuth2.0 for authorization for each of the different apps; for authentication we are currently using our own database (IDP)
We want to the end users to have a single sign on experience for this flow.
To have that we added openid on top of the OAuth flow we have built.
The web server has the standard oauth + openid implementation and has the following
Explicit Flow
Implicit Flow
Password Grant
On adding the openid connect, the server now has the ability to send the id_token (jwt) as well, depending on the scope and request type
There are two clients registered (C1 & C2)
Step 1: C1 follows explicit flow and uses response type as code, so when a user (U1) access C1 it is redirected to the authentication server where U1 enters the credentials.
Step 2: The authorization server validates the credentials and prompts for the user consent, confirming which sends out the code to the redirect_uri of C1
Step 3: C1 then requests for a token and the server gives out an access_token and an id_token; the access token being persisted in the database
Step 4: U1 now needs to access C2
Questions:
What would be the best way/practice for C2 to get the access token from the api sever without having the user to login again.
If C1 passes the jwt id_token to C2 through local-storage or any other means, one possible way would be to exchange the id_token for an access_token following this.
If we go with the above approach, would it be sufficient to just verify the id_token and issue the access_token or should we add any other check
Any other approach.
Thanks
Choice of flow will depend on type of client. For example, client could be a native application, which can use Authorization code flow (I guess you refer Explicit Flow to this flow). Or JavaScript application which solely run on browser.
Solution - Session cookie based SSO
In OAuth 2.0 (including OpenID Connect), end user (ex:- U1 as in your example) authentication occur through browser interaction. In this process, usually authorization server establish establish a session. What this session does is keeping a reference to previously authenticated user. For example, this allows user to access IDP and update user contented there (if your identity provider support such).
Now, if both applications use the same browser (ex:- Microsoft Edge) to show the login screen in authorization request of OpenID Connect, your authorization server can check session cookie existing with the browser.If this is the case, authorization server can skip login screen and response with relevant content. Following is sample scenario with a fresh login
C1 initiates authorization request, and redirects to the authorization endpoint
Authorization server receives the request and check for a session cookie.
Since this is a fresh start, no cookie exist, so login is present
User U1 login
Authorization server send response and C1 complete token obtaining
C2 initiates authorization request, and redirects to the authorization endpoint
Authorization server receives the request and check for a session cookie.
Since we are using the same browser, session cookie exists and correlated user is identified as U1
Authorization server send response and C2 complete token obtaining
Now both C1 and C2 have U1 user logged in to them. This is browser based SSO.
if those clients are web applications the best and recommended flow to use is the Implicit flow for some reasons:
it is secured in that case if you compare it with the hybrid flow, because the hybrid flow share a secret key with the clinet, and the client have to keep it, this key is used to generate acces_tokens, on the other side Implicit flow provide an access-token directly to the client with a short life time, so the best is to provide an access_token with short life time than an authorization key with long lifetime that can be used to generate tokens.
SSO (single sign on) will work perfectly between client that share the same STS server, so C2 can have an access_token without authentication, here is the steps:
C1 authenticate and get and id-token and an access_token
a session cookie is created for this active session
C2 click login and will get directly an access_token without authentication because the browser will send a valid cookie created from C1 authentication
Lets say I have a web API that a native application needs to make requests to. This API needs to authenticate who the user is that's making these requests via the native app. OpenID Connect seems to be the right choice since it is about authentication rather than authorization with OAuth.
The native app sends the users credentials to the IDP and gets back an access token (for authorization) and an id token (for authentication). From what I understand of OIDC, the access token would be sent to the API but the id token is only for the native client app. That doesn't make sense to me because it's the API that cares about who the user is, not the native app.
So why isn't the id token also passed to the protected resource (aka the API)? If you don't pass the id token to the API, what guarantees that the access token is secure and can be used to authenticate the user? Otherwise it would seem to lose the benefit of using OIDC over OAuth.
The OIDC Specification is designed in a way that ID tokens are always for Clients (Native app) and Access tokens are for resources (APIs). The ID tokens are always JWT tokens, but the Access tokens can be of different type.
The purpose of Access token is not to authenticate but to Authorize (Delegated Authorization). If, for some reason, the resource server wanted to know about the user, it can call the user-info endpoint.
The security/validity of token exchange can be validated in several ways:
Using encryption/signature with Public/Private key model where Authorization server encrypts / signs the access token with its private key and resource server decrypts / verifies with the public key.
Using token introspection endpoint to validate the claims, validity of the token etc..
Other attributes like AUD , AZP help in validating the issued access tokens.
Some OIDC providers use ID_Tokens to access API's - this is different to the model suggested by OIDC specification
This article has detailed explanation about these scenarios.
I would like to give the users a possibility to login with some external oauth2 provider (facebook) in my app. The client's part is running on mobile device in a native app.
I am not sure which of the approaches below should I prefer ?
Should the client send the user's access token by facebook with each request ? At each request backend asks facebook to validate the access token. Based on the validation's result, backend performs authorization and return corresponding result to the client.
Should the backend ask facebook to validate the access token only at user logon, then issue its own access token, return the access token back to the client and client will use this access token at making requests to the server to avoid contacting facebook at each request ?
I have read some questions about how to implement the auth with facebook and most of the devs are using B, but I haven't seen any explanation why is it good/bad to use A ?
What I see as benefits of the solutions:
backend doesn't need to care about issuing, refreshing, validating access tokens since this is done only by facebook's authorization servers.
this solution seems to be more effective, since it does not require to connect to facebook at each request.
Security tokens issued by Facebook are signed with a digital signature. The API server only needs access to the public key to validate the signature. There's no need at all to contact Facebook after the user authenticates.
A reason to issue your own tokens after the user signed in with Facebook could be to add claims to the token. But obviously having your own authorization server comes at a cost. It's up to you to weigh the pros and cons.
If you do decide to have your own authorization server, make sure not to write your own! There are open source options like Thinktecture IdentityServer.
I will vote for option B and here is my explanation,
Your API must authorise the request every time with some auth token , which cannot be external provider token, in such case anyone with an access token (eg: other developers) of other provider can access your api, basically there is no auth here.
When your sever issue access token, it's easy to validate and when needed could be revoked easily (eg: on password reset)
While authenticating , your server has fully control over issuing access token , so the validation is made only once and doesn't have to do every time while calling the API.