I am working with a couple of applications which are created in apps.dev.microsoft.com. The auth URL I am using is
https: //login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id={client_id}
&redirect_uri={redirect_uri}
&response_type=code id_token
&state=state
&nonce=c7a966a3-d63d-4348-8ab8-bd445b0e9bb1
&response_mode=form_post
&scope=openid email profile https://graph.microsoft.com/user.readBasic.all
In my use case, I am capturing tid, oid, iss, sub... claims from id_token claims.
For one of my application, with some users the oid claim is missing in the id_token. But I am able to get for other apps and I don't see any difference in creating apps.
What reasons might cause the oid claim to be missing?
Scopes I am using: openid email user.read
The oid claim will only be returned if the scope profile was requested.
From the documentation:
Because the oid allows multiple apps to correlate users, the profile scope is required in order to receive this claim.
For users where you don't receive the oid claim, check the token to make sure the profile scope is there. If it isn't there (and you've confirmed it was requested) then you can force the scopes for that token to be refreshed by adding &prompt=consent to the end of your authentication URI. This will force the user to re-consent to the scopes and ensure you're not getting a cached token.
Related
I am missing some understanding of OAuth2 access_token hope someone can explain or guide me to what I am missing.
I am using Microsoft Azure AD as an authentication provider for my application, I used the returned id_token after successful authentication to extend it with some additional data custom to my application (to facilitate authorization).
I am doing this throw JWT.sign, I decode the data from id_token and add data then I sign it using a secret key saved at the server.
My question is, can I do the same for access_token? When I tried to do so, I get unauthorized.
Am I doing something wrong? Or this is not possible? And why is this happening, I don't find any request made to MS to validated my new signed access_token.
You should never change tokens issued - this is not a correct thing to do. But your point about using domain specific claims is totally valid - all real world systems need these for their authorization.
OPTION 1
Some specialist providers can reach out at time of token issuance and contact your APIs, to get domain specific data to include in tokens. See this Curity article for how that works. I don't think Azure AD supports this though.
PRIVACY
It is best to avoid revealing sensitive data in readable tokens returned to internet clients. If you include name, email etc in ID tokens or access tokens this may be flagged up in PEN tests, since it is Personally Identifiable Information and revealing it can conflict with regulations such as GDPR.
Curity recommends protecting access tokens by issuing them in an opaque reference token format - via the phantom token pattern.
OPTION 2
An option that would work fir Azure AD is to adopt the following approaches:
Look up extra domain specific claims in your API when an access token is first received, then cache results for further API requests with the same access token. See this Azure AD Code Sample class of mine for some code that builds a custom ClaimsPrincipal. Note that the API continues to validate the JWT on every request.
If the UI needs extra domain specific claims then serve them from your API, which can return both OAuth User Info and domain specific data from its ClaimsPrincipal to the UI. See this API controller class for how that looks. Personally I always do this and never read ID tokens in UIs - which should also never read access tokens.
Applications interacting with Azure AD, receive ID tokens after authenticating the users. The applications use access tokens and refresh tokens while interacting with APIs.
The id_token is a JSON Web Token (JWT) which has user profile
attributes in the form of claims. The ID Token is consumed by the
application and used to get user information like the user's name,
email.
The Access Token on the otherhand is a credential that can be
used by an application to access an API.
So if you need application to access api, there the access token is used and you may follow the suggestion steps provided by Tiny Wang
Similar to id tokens, access tokens are also signed, but they are not
encrypted. As per IETF OAuth (RFC 6749) standard specification ,
access token can have different formats and structures for each
services whereas, id token should be JWT format.
To validate an id_token or an access_token, your app has to validate
both the token's signature and the claims. To validate access tokens,
your app should also validate the issuer, the audience, and the
signing tokens.
So in production application, you should get id token by specifying
“id_token+code” or “id_token+token” as response_type to verify
whether the authentication is correctly succeeded. It means it uses
the id_token for authentication and “code” to exchange access_token
to access the resource for authorization.
In short id_token is used to identify the authenticated user, and the
access token is used to prove access rights to protected resources.
Refer this for the information regarding access token and id token.
Using Gitlab provided access tokens for the OpenID scope, i.e.
https://gitlab.com/oauth/userinfo?access_token=<bearer token>
returns a limited amount of information e.g. username, groups, etc. However, it does not return the user's email address.
The Gitlab documentation indicates that:
The claims sub, sub_legacy, email and email_verified are included in
the ID token, all other claims are available from the /oauth/userinfo
endpoint used by OIDC clients.
Given the AccessToken - how do I retrieve the ID token?
*This is a known / discussed issue cf. here
It all depends on what scopes you ask for when you first send the initial authentication request to GitLab.
You need to ask for the email scope to get that information back and you should get the ID-token back at the same time as you get your first access-token.
When you obtain code through authorization request, you need to specify the scope, and the scope needs to include openid,read_user,profile,email.
When exchanging the token with the code obtained in the first step, you can return to access_token and id_token.
When the access_token obtained in the second step is used to obtain the user information, it can return the user's e-mail.
Refer to the explanation of the scope used above:
openid: Grants permission to authenticate with GitLab using OpenID Connect. Also gives read-only access to the user's profile and group memberships.
read_user: Grants read-only access to the authenticated user's profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users.
profile: Grants read-only access to the user's profile data using OpenID Connect.
email: Grants read-only access to the user's primary email address using OpenID Connect.
I am using the Resource Owner Password grant flow and requesting id token as well (the scope includes openid). I am sending the following to the endpoint:
client_id
client_secret
grant_type=password
username
password
scope
In the response I get the access token and the id token. The value for the sub claim is different between the two tokens. Why is this the case?
Update
It seems that the user id is actually an oid claim. This is described in Azure AD ID token reference.
Text describing the oid claim:
The immutable identifier for an object in the Microsoft identity system, in this case, a user account. This ID uniquely identifies the user across applications - two different applications signing in the same user will receive the same value in the oid claim. The Microsoft Graph will return this ID as the id property for a given user account. Because the oid allows multiple apps to correlate users, the profile scope is required in order to receive this claim. Note that if a single user exists in multiple tenants, the user will contain a different object ID in each tenant - they are considered different accounts, even though the user logs into each account with the same credentials.
Text describing the sub claim:
The principal about which the token asserts information, such as the user of an app. This value is immutable and cannot be reassigned or reused. The subject is a pairwise identifier - it is unique to a particular application ID. Therefore, if a single user signs into two different apps using two different client IDs, those apps will receive two different values for the subject claim. This may or may not be desired depending on your architecture and privacy requirements.
However, I am still not clear why the sub claim is different between the access and id tokens.
The subject (sub) claim is unique for the user and the service for which the token is intended (identified by the audience (aud) claim).
Usually, the ID Token and Access Token audiences will be different: the ID Token audience is the client app where the user is signing in, and the Access Token audience is the resource server the client app will attempt to access (on behalf of the signed-in user).
The Resource Owner Password Credentials grant type is not supposed to be used for user authentication as per the OpenID specification, only flow with that interact with the user through the authorization endpoint are allowed to do so (i.e. Implicit, Authorization Code, Hybrid and None grant type flows at the time of writing).
If you receive an ID token using the ROPC flow, then the Identity Provider proposes specific means that are out of scope of the OpenID Connect spec and may have specific and non-standard features that should be documented.
In any case, on Client side you should only rely on the sub claim in the ID Token. The Client is not supposed to parse the access token as it is only meant to be used by the resource server.
The sub claim depends on the IdP policy and the client configuration. The sub claim may be unique to the application (or application group). Please refer to Subject Identifier Types section of the specification.
I'm considering to use id token instead of id token for authorization, so that resource servers can validate its sign and extract user id out of it. Is there any dowside to this method which I'm not aware of?
I guess I cannot use verify endpoint if I throw away access token. For us, it doesn't matter which scope the user granted access to since both client app and OIDC's identity provider is owned by us.
I'm using this library to implement an OAuth2 and OpenID server.
https://github.com/bshaffer/oauth2-server-php
Usage of ID Token is intended for the client application. Client uses it to authenticate the end user. All this is made possible through claims ID Token transfer. And these claims are built into an JWT. In simple terms, ID Token is a self-contained token.
Now, sharing of ID Token outside of client is okay if you control all intended parties. Think about a scenario in which you leak sensitive user information through ID Token. For example if ID Token contain a claim about gender which only intended for client to use. But when you share ID Token with a third party, you expose those sensitive information. It could be a crime if there are legal barriers.
Another point is on ID Token validation. Hence ID Token targets the client, important claims such as aud is set accordingly. When you pass ID Token to a backend to be used, such validation could fail.
There are two solutions. First is to use self contained access tokens. These days it is common to use JWT based access tokens. With them, you get the same solution. It will contain end user identity, scope values as well as token validation information. Azure AD use such approach - check this link.
Second one is to use ID Token. Given that you control both front end and backend, my opinion is you are okay to use it. But be mindful about future extensions. Specially not to expose it to other parties.
Our Mobile Client App uses https://identityserver:port/oauth2/token service from Identity Server by passing the ClientID and ClientSecret with grant_type as “client_credentials” to generate the access token. The generated access token is used to invoke the API from ESB.
As per the implementation the ClientID and ClientSecret will be stored in the device.
For an example, ClientX requested for an Oauth Token which will have a certain expiry time. Can this token make as a unique for ClientX?
Currently all the upcoming client calls will get the same access token as its already generated from the request of ClientX. If a client is requesting a token very late it will get the same token with almost expiry time.
Is there a way to make this token unique for the Client?
In your case, if you use “client_credentials” as a grant type, resource owner is also the client.
Since this is a mobile application, once your mobile app gets the token it will be used until the expiry date and there will not be a necessity of changing it, because of mobile is belongs to a single user. Therefore the token would be same for same scope till it is expired.
Ex: BBC news mobile application.
If you need different access tokens, you need to use different scopes.
You will need different access token in case if different clients accessing the same API. In that case you may use “PASSWORD” grant type for a unique access token.
Ex: Purchasing a product using ebay.
So you should define your scope properly to identify the use of access token.
Find the following blog that will help you to guide to select your scope. [1]
[1] http://wso2.com/library/articles/2014/02/securing-your-web-service-with-oauth2-using-wso2-identity-server-1/
I will assume that mobile application instance is bound per user.
If you want to get different access tokens for every user bound to a session don't use client_credential grant type.
For example you have client-x and client-y both using client_credentials grant. Identity Server (Authorization Server) will give an access token for client-x and client-y since this is about authorizing client-x and client-y to access resource and not about authorizing a user. This means whatever user you have in client-x or client-y requesting access_token, they can get one (assuming they are authenticated).Vice versa, a user, even if authenticated both client and identity server cannot get an access token if the request comes from client-z (client-z is not registered in identity server)
If your Oauth 2.0 client is browser-based you can use implicit grant, if it is a server you can use either authorization grant or resource owner password credential.