{"_id":"5a0b0d9b04d0d600269f1387","category":{"_id":"5a0b0d9b04d0d600269f1376","version":"5a0b0d9b04d0d600269f1373","project":"573c7e3b9eef3a0e00b51c58","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-09-13T19:58:29.432Z","from_sync":false,"order":2,"slug":"itegration-guide","title":"Integration Guide"},"project":"573c7e3b9eef3a0e00b51c58","user":"573c7e0afe58321900f1b97d","version":{"_id":"5a0b0d9b04d0d600269f1373","project":"573c7e3b9eef3a0e00b51c58","__v":1,"createdAt":"2017-11-14T15:36:59.500Z","releaseDate":"2017-11-14T15:36:59.500Z","categories":["5a0b0d9b04d0d600269f1374","5a0b0d9b04d0d600269f1375","5a0b0d9b04d0d600269f1376","5a0b0d9b04d0d600269f1377","5a0b0d9b04d0d600269f1378"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"2.0.0","version":"2.0"},"githubsync":"","__v":0,"parentDoc":null,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-09-13T20:45:27.923Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"When a user tries to log in with Privakey, you will need to:\n1.\tCreate an anti-forgery state token\n2.\tSend an authentication request to Privakey\n3.\tConfirm the anti-forgery state token\n4.\tExchange code for access token and ID token\n5.\tObtain user information from the ID token\n6.\tAuthenticate the user\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"1. Create an anti-forgery state token\"\n}\n[/block]\n\nYou must protect the security of your users by preventing request forgery attacks. The first step is creating a unique session token that holds state between your app and the user's client. You later match this unique session token with the authentication response returned by the Privakey Authentication service to verify that the user is making the request and not a malicious attacker. These tokens are often referred to as cross-site request forgery (CSRF) tokens.\n\nOne good choice for a state token is a string of 30 or so characters constructed using a high-quality random-number generator. Another is a hash generated by signing some of your session state variables with a key that is kept secret on your back-end.\n\n## Example\nThe following code generates a simple state and stores it in the session, to be used later.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"using System; // Used for Convert\\nusing System.Security.Cryptography; // Used for RNGCryptoServiceProvider\\n\\n// Initialize the cryptographically strong Random object.\\nRNGCryptoServiceProvider random = new RNGCryptoServiceProvider();\\n\\n// Generate the state.\\nvar data = new byte[30];\\nrandom.GetNonZeroBytes(data);\\nSession[\\\"state\\\"] = Convert.ToBase64String(data);\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"get\",\n  \"title\": \"2. Send an authentication request to Privakey\"\n}\n[/block]\nThe next step is forming an HTTPS GET request with the appropriate URI parameters.  HTTPS must be used.  \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://idp.privakey.com/connect/authorize\",\n      \"language\": \"text\",\n      \"name\": \"API Endpoint for Authentication Request\"\n    }\n  ]\n}\n[/block]\n\nFor a basic request, specify the following parameters:\n•\t**client_id**, which you obtain from the Privakey Relying Party Administration console.\n•\t**response_type**, which in a basic request should be code.\n•\t**scope**, Designates the user information returned by the Privakey Service. Vales can include: `openid` for the user's GUID (SUB) only, `email` for their email address, and `profile` to receive their name.  The list should be space separated, for example:  `openid email profile`   \n•\t**redirect_uri** should be the HTTP endpoint on your server that will receive the response from Privakey. You specify this URI in the Privakey Relying Party Administration console.\n•\t**state** (recommended), An opaque value used to maintain state between the request and the callback. \n•\t**nonce**, A random string value used to associate a Client session with an ID Token\n\nHere is an example of a complete Privakey authentication URI, with line breaks and spaces for readability:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://idp.privakey.com/connect/authorize?\\n client_id=[client_id]&\\n response_type=code&\\n scope=openid%20email&\\n redirect_uri=[redirect_uri]&\\n state=[state_set]&\\n nonce=[nonce]\\n\",\n      \"language\": \"text\",\n      \"name\": \"Privakey Authentication URI Example\"\n    }\n  ]\n}\n[/block]\n## Example\nOur existing libraries will handle creation of this URI for you, so all you need to do is redirect to it. The following code snippet assumes you already implemented part 1, and have generated a state.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// NOTE: In order for this sample to work, you must specify your client ID \\n// and client secret in the project's web.config. For more information, view the sample\\n// code on github: https://github.com/privakey/privakey-dotnet\\n\\n// Grab the state out of the session, stored there in step 1.\\nstring state = Session[\\\"state\\\"];\\n\\n// Generate a nonce and store it in the session.\\nstring nonce = PrivaKeySignOn.generateNonce();\\nSession[\\\"nonce\\\"] = nonce;\\n\\n// Grab the email from the input field, or some other way.\\nstring email = textboxEmail.Text;\\n\\n// Redirect the user to the Privakey login URL.\\nResponse.Redirect(PrivaKeySignOn.getLoginURL(nonce, state, email));\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"fn\",\n  \"title\": \"3. Confirm anti-forgery state token\"\n}\n[/block]\nAfter a user authorizes the request, a response from the Privakey Authentication Service is sent to the redirect_uri that you specified in the request. All responses are returned in the query string.  An example is shown below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://[relying_party_redirect_uri]/code?state=[state_set]&code=[token_from_PAS]\",\n      \"language\": \"http\",\n      \"name\": \"Query String\"\n    }\n  ]\n}\n[/block]\nOn the server, you must confirm that the state received from the Privakey Authentication Service matches the session token you created. This round-trip verification helps to ensure that the user, not a malicious script, is making the request.\n\nThe state parameter should be used to maintain the session state (if any) that existed prior to the authorization request.\n\n## Example\nThe following code builds off of the example in step 1. When Privakey redirects back to your site, check the returned state against the state that you stored in the session.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if(Request.QueryString[\\\"state\\\"].Equals(Session[\\\"state\\\"] as string))\\n{\\n  // Once the returned state is verified, you are free to continue.\\n}\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"post\",\n  \"title\": \"4. Exchange code for access token and ID token\"\n}\n[/block]\nThe response includes a code parameter, a one-time authorization code that your server can use to request the Privakey Authentication Service for an access token and ID token. Your server makes this exchange by sending an HTTPS POST request to: \n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"https://idp.privakey.com/connect/token\",\n      \"language\": \"http\"\n    }\n  ]\n}\n[/block]\nThe request should include the following parameters in the POST body:\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Parameter\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"code\",\n    \"1-0\": \"redirect_uri\",\n    \"2-0\": \"grant_type\",\n    \"0-1\": \"The authorization code that is returned from the initial request.\",\n    \"1-1\": \"The URI that you specify in the Privakey Relying Party Administration Console\",\n    \"2-1\": \"This field must contain a value of authorization_code\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]\nThe client_id and client_secret should be provided in a Basic Authorization Header, a Base64 encoded client id and secret from the Privakey User Portal, in the format \"Basic <base64 client_id:client_secret>\". \n\nIf the client_id and client_secret cannot be provided in a Basic Authorization Header, they can be included in the POST body:\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Parameter\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"client_id\",\n    \"0-1\": \"The client ID that you obtain from the Privakey Relying Party Administration Console\",\n    \"1-0\": \"client_secret\",\n    \"1-1\": \"The client secret that you obtained from the Privakey Relying Party Administration Console\"\n  },\n  \"cols\": 2,\n  \"rows\": 2\n}\n[/block]\nA successful response to this request contains the following fields in a JSON array:\n\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Key\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"access_token\",\n    \"0-1\": \"A token that can be sent to obtain user information and access information from a Privakey API.\",\n    \"1-0\": \"id_token\",\n    \"1-1\": \"A JWT that contains identity information about the user that is digitally signed by the Privakey Authentication Service\",\n    \"2-0\": \"expires_in\",\n    \"2-1\": \"The remaining lifetime of the access token.\",\n    \"3-1\": \"Identifies the type of token returned. At this time, this field always has the value Bearer.\",\n    \"3-0\": \"token_type\"\n  },\n  \"cols\": 2,\n  \"rows\": 4\n}\n[/block]\n## Example\nThe following code demonstrates how to trade the code for the ID token using our library, which simplifies the process. This example is expanded upon in step 5, to show how to retrieve the user identifier from the ID token.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if(Request.QueryString[\\\"code\\\"] != null)\\n{\\n  string idToken = PrivaKeySignOn.getIDToken(Request.QueryString[\\\"code\\\"]);\\n}\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"5.\\tObtain user information from the ID token\"\n}\n[/block]\nThe ID Token is a JWT (JSON Web Token), that is, a cryptographically signed Base64-encoded JSON object. Normally, it is critical that you validate an ID token before you use it, but since you are communicating directly with the Privakey Authentication Service over an intermediary-free HTTPS channel and using your client secret to authenticate, you can be confident that the token you receive is valid. If your server passes the ID token to other components of your app, it is extremely important that the other components validate the token before using it.\n\nSince most API libraries combine the validation with the work of decoding the base64 and parsing the JSON, you will probably end up validating the token anyway as you access the fields in the ID token.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n \\\"iss\\\":\\\"idp.privakey.com\\\",\\n \\\"at_hash\\\":\\\"[at_hash]\\\",\\n \\\"sub\\\":\\\"10769150350006150715113082367\\\",\\n \\\"azp\\\":\\\"[client_id]\\\",\\n \\\"email\\\":\\\"jsmith:::at:::example.com\\\",\\n \\\"aud\\\":\\\"[client_id]\\\",\\n \\\"iat\\\":1573214062,\\n \\\"exp\\\":1573207962 \\n}\\n\",\n      \"language\": \"json\",\n      \"name\": \"An ID Token's Payload, Example\"\n    }\n  ]\n}\n[/block]\nPrivakey ID Tokens may contain the following fields (known as claims):\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"iss\",\n    \"0-1\": \"The Issuer Identifier for the Issuer of the response. Always idp.privakey.com.\",\n    \"1-0\": \"at_hash\",\n    \"1-1\": \"Access token hash. Provides validation that the access token is tied to the identity token. If the ID token is issued with an access token in the server flow, this is always included. This can be used as an alternate mechanism to protect against cross-site request forgery attacks.\",\n    \"2-0\": \"**sub**\",\n    \"2-1\": \"An identifier for the user, unique among all Privakey accounts and never reused. A Privakey account may have multiple emails at different points in time, but the sub value is never changed. **Use sub within your application as the unique-identifier key for the user.**\",\n    \"3-0\": \"azp\",\n    \"3-1\": \"The client_id of the authorized presenter. This claim is only needed when the party requesting the ID token is not the same as the audience of the ID token.\",\n    \"4-0\": \"email\",\n    \"4-1\": \"The user's email address. This may not be unique and is not suitable for use as a primary key. Provided only if your scope included the string \\\"email\\\".\",\n    \"5-0\": \"profile\",\n    \"5-1\": \"The URL of the user's profile page. Might be provided when the request scope included the string \\\"profile\\\" or the ID token is returned from a token refresh. When profile claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.\",\n    \"6-0\": \"name\",\n    \"6-1\": \"The user's full name, in a displayable form. Might be provided when the request scope included the string \\\"profile\\\" or the ID token is returned from a token refresh. When name claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.\",\n    \"7-0\": \"aud\",\n    \"7-1\": \"Identifies the audience that this ID token is intended for. It must be one of the client IDs configured in the Privakey Relying Party Administration console for your application.\",\n    \"8-0\": \"iat\",\n    \"8-1\": \"The time the ID token was issued, represented in Unix time (integer seconds).\",\n    \"9-0\": \"exp\",\n    \"9-1\": \"The time the ID token expires, represented in Unix time (integer seconds).\",\n    \"h-0\": \"Claim\",\n    \"h-1\": \"Description\"\n  },\n  \"cols\": 2,\n  \"rows\": 10\n}\n[/block]\n##Example\nThe following code retrieves the code from the request, exchanges it for an ID token from Privakey, and then validates the ID token and retrieves the user identifier.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if(Request.QueryString[\\\"code\\\"] != null)\\n{\\n  // Retrieve the ID token from Privakey\\n  string idToken = PrivaKeySignOn.getIDToken(Request.QueryString[\\\"code\\\"]);\\n  \\n  // Retrieve the nonce from the session, it was stored there in step 2.\\n  string nonce = Session[\\\"nonce\\\"] as string;\\n  \\n  // Validate the ID token and, if it is valid, retrieve the user's identifier from it.\\n  string userIdentifier;\\n  if(PrivaKeySignOn.isValidToken(idToken, nonce, out userIdentifier))\\n  {\\n    // Use the userIdentifier to log the user in.\\n  }\\n}\",\n      \"language\": \"csharp\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"6.\\tAuthenticate the user\"\n}\n[/block]\nTo prepare your service for Privakey you will need to extend your user model to include the Privakey user GUID returned in the ID Token sub parameter.  You may also want to extend the model to account for the authentication method the user is using (i.e. Username and Password or Privakey).  This can be done in a number of ways. It is a best practice to disable Username and Password authentication for users who have chosen to use Privakey.  To minimize your liability and your users’ exposures you should also delete any hashed user passwords stored in your database for users who opt to use Privakey.   \n\nAfter obtaining user information from the ID token, you should query your app's user database for the sub identifier. If the user already exists in your database, you should start an application session for that user.\n\nIf the user does not exist in your user database, you should redirect the user to your new-user sign-up flow. Depending on the details you require to complete a registration, you may be able to auto-register the user based on the information you receive from Privakey.\n\nAlternatively, you should be able to pre-populate the Name and Email Address fields that you may require on your registration form.","excerpt":"Implement OpenID Connect Calls to Enable Privakey Authentication","slug":"privakey-authentication","type":"basic","title":"Privakey Authentication"}

Privakey Authentication

Implement OpenID Connect Calls to Enable Privakey Authentication

When a user tries to log in with Privakey, you will need to: 1. Create an anti-forgery state token 2. Send an authentication request to Privakey 3. Confirm the anti-forgery state token 4. Exchange code for access token and ID token 5. Obtain user information from the ID token 6. Authenticate the user [block:api-header] { "type": "basic", "title": "1. Create an anti-forgery state token" } [/block] You must protect the security of your users by preventing request forgery attacks. The first step is creating a unique session token that holds state between your app and the user's client. You later match this unique session token with the authentication response returned by the Privakey Authentication service to verify that the user is making the request and not a malicious attacker. These tokens are often referred to as cross-site request forgery (CSRF) tokens. One good choice for a state token is a string of 30 or so characters constructed using a high-quality random-number generator. Another is a hash generated by signing some of your session state variables with a key that is kept secret on your back-end. ## Example The following code generates a simple state and stores it in the session, to be used later. [block:code] { "codes": [ { "code": "using System; // Used for Convert\nusing System.Security.Cryptography; // Used for RNGCryptoServiceProvider\n\n// Initialize the cryptographically strong Random object.\nRNGCryptoServiceProvider random = new RNGCryptoServiceProvider();\n\n// Generate the state.\nvar data = new byte[30];\nrandom.GetNonZeroBytes(data);\nSession[\"state\"] = Convert.ToBase64String(data);", "language": "csharp" } ] } [/block] [block:api-header] { "type": "get", "title": "2. Send an authentication request to Privakey" } [/block] The next step is forming an HTTPS GET request with the appropriate URI parameters. HTTPS must be used. [block:code] { "codes": [ { "code": "https://idp.privakey.com/connect/authorize", "language": "text", "name": "API Endpoint for Authentication Request" } ] } [/block] For a basic request, specify the following parameters: • **client_id**, which you obtain from the Privakey Relying Party Administration console. • **response_type**, which in a basic request should be code. • **scope**, Designates the user information returned by the Privakey Service. Vales can include: `openid` for the user's GUID (SUB) only, `email` for their email address, and `profile` to receive their name. The list should be space separated, for example: `openid email profile` • **redirect_uri** should be the HTTP endpoint on your server that will receive the response from Privakey. You specify this URI in the Privakey Relying Party Administration console. • **state** (recommended), An opaque value used to maintain state between the request and the callback. • **nonce**, A random string value used to associate a Client session with an ID Token Here is an example of a complete Privakey authentication URI, with line breaks and spaces for readability: [block:code] { "codes": [ { "code": "https://idp.privakey.com/connect/authorize?\n client_id=[client_id]&\n response_type=code&\n scope=openid%20email&\n redirect_uri=[redirect_uri]&\n state=[state_set]&\n nonce=[nonce]\n", "language": "text", "name": "Privakey Authentication URI Example" } ] } [/block] ## Example Our existing libraries will handle creation of this URI for you, so all you need to do is redirect to it. The following code snippet assumes you already implemented part 1, and have generated a state. [block:code] { "codes": [ { "code": "// NOTE: In order for this sample to work, you must specify your client ID \n// and client secret in the project's web.config. For more information, view the sample\n// code on github: https://github.com/privakey/privakey-dotnet\n\n// Grab the state out of the session, stored there in step 1.\nstring state = Session[\"state\"];\n\n// Generate a nonce and store it in the session.\nstring nonce = PrivaKeySignOn.generateNonce();\nSession[\"nonce\"] = nonce;\n\n// Grab the email from the input field, or some other way.\nstring email = textboxEmail.Text;\n\n// Redirect the user to the Privakey login URL.\nResponse.Redirect(PrivaKeySignOn.getLoginURL(nonce, state, email));", "language": "csharp" } ] } [/block] [block:api-header] { "type": "fn", "title": "3. Confirm anti-forgery state token" } [/block] After a user authorizes the request, a response from the Privakey Authentication Service is sent to the redirect_uri that you specified in the request. All responses are returned in the query string. An example is shown below: [block:code] { "codes": [ { "code": "https://[relying_party_redirect_uri]/code?state=[state_set]&code=[token_from_PAS]", "language": "http", "name": "Query String" } ] } [/block] On the server, you must confirm that the state received from the Privakey Authentication Service matches the session token you created. This round-trip verification helps to ensure that the user, not a malicious script, is making the request. The state parameter should be used to maintain the session state (if any) that existed prior to the authorization request. ## Example The following code builds off of the example in step 1. When Privakey redirects back to your site, check the returned state against the state that you stored in the session. [block:code] { "codes": [ { "code": "if(Request.QueryString[\"state\"].Equals(Session[\"state\"] as string))\n{\n // Once the returned state is verified, you are free to continue.\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "post", "title": "4. Exchange code for access token and ID token" } [/block] The response includes a code parameter, a one-time authorization code that your server can use to request the Privakey Authentication Service for an access token and ID token. Your server makes this exchange by sending an HTTPS POST request to: [block:code] { "codes": [ { "code": "https://idp.privakey.com/connect/token", "language": "http" } ] } [/block] The request should include the following parameters in the POST body: [block:parameters] { "data": { "h-0": "Parameter", "h-1": "Description", "0-0": "code", "1-0": "redirect_uri", "2-0": "grant_type", "0-1": "The authorization code that is returned from the initial request.", "1-1": "The URI that you specify in the Privakey Relying Party Administration Console", "2-1": "This field must contain a value of authorization_code" }, "cols": 2, "rows": 3 } [/block] The client_id and client_secret should be provided in a Basic Authorization Header, a Base64 encoded client id and secret from the Privakey User Portal, in the format "Basic <base64 client_id:client_secret>".  If the client_id and client_secret cannot be provided in a Basic Authorization Header, they can be included in the POST body: [block:parameters] { "data": { "h-0": "Parameter", "h-1": "Description", "0-0": "client_id", "0-1": "The client ID that you obtain from the Privakey Relying Party Administration Console", "1-0": "client_secret", "1-1": "The client secret that you obtained from the Privakey Relying Party Administration Console" }, "cols": 2, "rows": 2 } [/block] A successful response to this request contains the following fields in a JSON array: [block:parameters] { "data": { "h-0": "Key", "h-1": "Description", "0-0": "access_token", "0-1": "A token that can be sent to obtain user information and access information from a Privakey API.", "1-0": "id_token", "1-1": "A JWT that contains identity information about the user that is digitally signed by the Privakey Authentication Service", "2-0": "expires_in", "2-1": "The remaining lifetime of the access token.", "3-1": "Identifies the type of token returned. At this time, this field always has the value Bearer.", "3-0": "token_type" }, "cols": 2, "rows": 4 } [/block] ## Example The following code demonstrates how to trade the code for the ID token using our library, which simplifies the process. This example is expanded upon in step 5, to show how to retrieve the user identifier from the ID token. [block:code] { "codes": [ { "code": "if(Request.QueryString[\"code\"] != null)\n{\n string idToken = PrivaKeySignOn.getIDToken(Request.QueryString[\"code\"]);\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "basic", "title": "5.\tObtain user information from the ID token" } [/block] The ID Token is a JWT (JSON Web Token), that is, a cryptographically signed Base64-encoded JSON object. Normally, it is critical that you validate an ID token before you use it, but since you are communicating directly with the Privakey Authentication Service over an intermediary-free HTTPS channel and using your client secret to authenticate, you can be confident that the token you receive is valid. If your server passes the ID token to other components of your app, it is extremely important that the other components validate the token before using it. Since most API libraries combine the validation with the work of decoding the base64 and parsing the JSON, you will probably end up validating the token anyway as you access the fields in the ID token. [block:code] { "codes": [ { "code": "{\n \"iss\":\"idp.privakey.com\",\n \"at_hash\":\"[at_hash]\",\n \"sub\":\"10769150350006150715113082367\",\n \"azp\":\"[client_id]\",\n \"email\":\"jsmith@example.com\",\n \"aud\":\"[client_id]\",\n \"iat\":1573214062,\n \"exp\":1573207962 \n}\n", "language": "json", "name": "An ID Token's Payload, Example" } ] } [/block] Privakey ID Tokens may contain the following fields (known as claims): [block:parameters] { "data": { "0-0": "iss", "0-1": "The Issuer Identifier for the Issuer of the response. Always idp.privakey.com.", "1-0": "at_hash", "1-1": "Access token hash. Provides validation that the access token is tied to the identity token. If the ID token is issued with an access token in the server flow, this is always included. This can be used as an alternate mechanism to protect against cross-site request forgery attacks.", "2-0": "**sub**", "2-1": "An identifier for the user, unique among all Privakey accounts and never reused. A Privakey account may have multiple emails at different points in time, but the sub value is never changed. **Use sub within your application as the unique-identifier key for the user.**", "3-0": "azp", "3-1": "The client_id of the authorized presenter. This claim is only needed when the party requesting the ID token is not the same as the audience of the ID token.", "4-0": "email", "4-1": "The user's email address. This may not be unique and is not suitable for use as a primary key. Provided only if your scope included the string \"email\".", "5-0": "profile", "5-1": "The URL of the user's profile page. Might be provided when the request scope included the string \"profile\" or the ID token is returned from a token refresh. When profile claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.", "6-0": "name", "6-1": "The user's full name, in a displayable form. Might be provided when the request scope included the string \"profile\" or the ID token is returned from a token refresh. When name claims are present, you can use them to update your app's user records. Note that this claim is never guaranteed to be present.", "7-0": "aud", "7-1": "Identifies the audience that this ID token is intended for. It must be one of the client IDs configured in the Privakey Relying Party Administration console for your application.", "8-0": "iat", "8-1": "The time the ID token was issued, represented in Unix time (integer seconds).", "9-0": "exp", "9-1": "The time the ID token expires, represented in Unix time (integer seconds).", "h-0": "Claim", "h-1": "Description" }, "cols": 2, "rows": 10 } [/block] ##Example The following code retrieves the code from the request, exchanges it for an ID token from Privakey, and then validates the ID token and retrieves the user identifier. [block:code] { "codes": [ { "code": "if(Request.QueryString[\"code\"] != null)\n{\n // Retrieve the ID token from Privakey\n string idToken = PrivaKeySignOn.getIDToken(Request.QueryString[\"code\"]);\n \n // Retrieve the nonce from the session, it was stored there in step 2.\n string nonce = Session[\"nonce\"] as string;\n \n // Validate the ID token and, if it is valid, retrieve the user's identifier from it.\n string userIdentifier;\n if(PrivaKeySignOn.isValidToken(idToken, nonce, out userIdentifier))\n {\n // Use the userIdentifier to log the user in.\n }\n}", "language": "csharp" } ] } [/block] [block:api-header] { "type": "basic", "title": "6.\tAuthenticate the user" } [/block] To prepare your service for Privakey you will need to extend your user model to include the Privakey user GUID returned in the ID Token sub parameter. You may also want to extend the model to account for the authentication method the user is using (i.e. Username and Password or Privakey). This can be done in a number of ways. It is a best practice to disable Username and Password authentication for users who have chosen to use Privakey. To minimize your liability and your users’ exposures you should also delete any hashed user passwords stored in your database for users who opt to use Privakey. After obtaining user information from the ID token, you should query your app's user database for the sub identifier. If the user already exists in your database, you should start an application session for that user. If the user does not exist in your user database, you should redirect the user to your new-user sign-up flow. Depending on the details you require to complete a registration, you may be able to auto-register the user based on the information you receive from Privakey. Alternatively, you should be able to pre-populate the Name and Email Address fields that you may require on your registration form.